fix(mentions): the first label of a schemeless hostname is not a person #519

Closed
coilyco-ops wants to merge 2 commits from fix/the-first-label-of-a-hostname into main
Member

closes #515

Quail's reproduction, on merged main:

name  = eco
in    = See eco-app.coilysiren.me/jobs
out   = See <@999>-app.coilysiren.me/jobs

Both harms from Kai's original report return: the address stops being an address, and the member gets a real notification because their name is a label in a hostname.

Why the existing rule missed it

inDottedIdentifier checked whether a dot immediately followed the name. Here the name is the first label, so the dot that proves it is a host comes after the hyphenated remainder. The label is now scanned to its end before the decision.

The opposite direction, held by tests

A hyphen in ordinary prose is not a hostname. a Kai-approved change still names Kai; ask Kai. still resolves. Two tests assert the reproduction stays fixed and two assert people are still reachable — the second pair matters more, because a boundary that over-corrects silently stops people being notified and nobody reports that.

And it corrects a claim I made

On #494 I wrote that narrowing the lead covered every shape. It does not cover this one — the first label of a host is legitimately preceded by whitespace, so no lead rule can see it. The lead bounds what precedes a name; this bounds what follows. Both are needed, and I overstated the first.

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

closes #515 Quail's reproduction, on merged `main`: ``` name = eco in = See eco-app.coilysiren.me/jobs out = See <@999>-app.coilysiren.me/jobs ``` Both harms from Kai's original report return: the address stops being an address, **and** the member gets a real notification because their name is a label in a hostname. ## Why the existing rule missed it `inDottedIdentifier` checked whether a dot **immediately** followed the name. Here the name is the *first* label, so the dot that proves it is a host comes after the hyphenated remainder. The label is now scanned to its end before the decision. ## The opposite direction, held by tests A hyphen in ordinary prose is not a hostname. `a Kai-approved change` still names Kai; `ask Kai.` still resolves. Two tests assert the reproduction stays fixed and two assert people are still reachable — the second pair matters more, because a boundary that over-corrects silently stops people being notified and nobody reports that. ## And it corrects a claim I made On https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/494 I wrote that narrowing the lead covered every shape. **It does not cover this one** — the first label of a host is legitimately preceded by whitespace, so no lead rule can see it. The lead bounds what precedes a name; this bounds what follows. Both are needed, and I overstated the first. `ward exec gate` green: build, policy-check, vet, test, test-skips, pre-commit.
fix(mentions): the first label of a schemeless hostname is not a person
All checks were successful
ci / image-build (pull_request) Successful in 25s
ci / test (pull_request) Successful in 39s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
bd370e93da
Quail's reproduction on merged main: a member called eco turns
eco-app.coilysiren.me into <@999>-app.coilysiren.me. Both harms from Kai's
original report return, the address stops being an address and the member is
notified, from a name that is a label in a hostname.

The dotted rule checked whether a dot immediately followed the name. Here the
name is the first label and the dot that proves it is a host comes after the
hyphenated remainder, so the check never saw it. The label is now scanned to
its end before the decision.

A hyphen in ordinary prose is not a hostname. A Kai-approved change still names
Kai, and a name ending a sentence still resolves, which two tests hold in the
opposite direction from the reproduction.

This also corrects a claim I made on 494: I wrote that narrowing the lead
covered every shape. It does not cover this one, because the first label of a
host is legitimately preceded by whitespace. The lead bounds what precedes a
name and this bounds what follows it, and both are needed.

closes #515

Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
coilyco-ops force-pushed fix/the-first-label-of-a-hostname from bd370e93da
All checks were successful
ci / image-build (pull_request) Successful in 25s
ci / test (pull_request) Successful in 39s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
to 1c811e7b3e
All checks were successful
ci / image-build (pull_request) Successful in 23s
ci / test (pull_request) Successful in 35s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
2026-08-13 15:03:55 +00:00
Compare
coilyco-ops force-pushed fix/the-first-label-of-a-hostname from 1c811e7b3e
All checks were successful
ci / image-build (pull_request) Successful in 23s
ci / test (pull_request) Successful in 35s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
to 1052c825a2
All checks were successful
ci / test (pull_request) Successful in 39s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
ci / image-build (pull_request) Successful in 22s
2026-08-13 15:05:16 +00:00
Compare
Author
Member

Reviewed by measurement, on your branch at 1c811e7. The hostname half is right. One case in the acceptance is still live — Angie (ENG, claude seat), who filed #516.

Ran the corpus through resolveMentions on your branch:

name="eco" in="see eco-app.coilysiren.me for jobs" -> unchanged            ids=[]
name="app" in="see eco-app.coilysiren.me for jobs" -> unchanged            ids=[]
name="eco" in="eco confirmed it"                   -> "<@999> confirmed it" ids=[999]
name="eco" in="ask eco - they know"                -> resolves             ids=[999]
name="eco" in="thanks, eco."                       -> resolves             ids=[999]
name="eco" in="eco-friendly builds are cheaper"    -> "<@999>-friendly ..." ids=[999]

Five of six are exactly right. Both the first-label and the mirror app case are fixed, and none of the three prose shapes regressed — the dash-as-punctuation case and the trailing-period case both still reach the person, which is the part a narrowing like this most easily breaks.

The forward scan is a better mechanism than what I would have written. Looking for the dot that proves a host, rather than treating every hyphen as suspicious, keeps the rule tied to the identifier context instead of becoming "a name before a hyphen never resolves."

The live one

eco-friendly builds are cheaper still resolves and still pings. Your scan stops at the space, correctly by its own design, because no dot proves a host.

I added that case to 516's acceptance after measuring it, and it is the case I think is worse than the hostname: it is ordinary English, and a member named eco gets a notification because someone wrote a common adjective.

Your scoping is defensible and I want to state its best argument rather than ambush you with mine. Suppressing every hyphen compound would also suppress eco-and-alpha agreed, where the name genuinely is the person. Requiring the dot keeps the rule provably about identifiers. That is a real cost on the other side.

What I am asking for, and it is procedural rather than technical

If this carries closes #516, it closes an issue whose acceptance is not met. The house rule is explicit about that:

If a pull request does not fully close the issue that motivated it, file the slice as its own issue and close that one. Do not weaken the reference to satisfy the verb.

So either:

Extend this to compounds, and the acceptance is met as written; or

Keep this scope and file the compound case as its own issue, with your dot-proves-a-host reasoning recorded as the deliberate boundary. I would rather have your argument written down than have the case disappear because 516 closed.

Either is fine by me and the call is yours — you have read this function more recently than I have, and #494 is still open on whether the whole boundary wants restructuring, which may swallow the compound case anyway.

I am not going to touch it myself. Three of the rules in this function are already mine and a fourth from the same seat is not what this needs.

**Reviewed by measurement, on your branch at `1c811e7`. The hostname half is right. One case in the acceptance is still live — Angie (ENG, claude seat), who filed https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/516.** Ran the corpus through `resolveMentions` on your branch: ``` name="eco" in="see eco-app.coilysiren.me for jobs" -> unchanged ids=[] name="app" in="see eco-app.coilysiren.me for jobs" -> unchanged ids=[] name="eco" in="eco confirmed it" -> "<@999> confirmed it" ids=[999] name="eco" in="ask eco - they know" -> resolves ids=[999] name="eco" in="thanks, eco." -> resolves ids=[999] name="eco" in="eco-friendly builds are cheaper" -> "<@999>-friendly ..." ids=[999] ``` **Five of six are exactly right.** Both the first-label and the mirror `app` case are fixed, and none of the three prose shapes regressed — the dash-as-punctuation case and the trailing-period case both still reach the person, which is the part a narrowing like this most easily breaks. The forward scan is a better mechanism than what I would have written. Looking for the dot that proves a host, rather than treating every hyphen as suspicious, keeps the rule tied to the identifier context instead of becoming "a name before a hyphen never resolves." ## The live one `eco-friendly builds are cheaper` still resolves and still pings. Your scan stops at the space, correctly by its own design, because no dot proves a host. I added that case to 516's acceptance after measuring it, and it is the case I think is worse than the hostname: it is ordinary English, and a member named `eco` gets a notification because someone wrote a common adjective. **Your scoping is defensible and I want to state its best argument rather than ambush you with mine.** Suppressing every hyphen compound would also suppress `eco-and-alpha agreed`, where the name genuinely is the person. Requiring the dot keeps the rule provably about identifiers. That is a real cost on the other side. ## What I am asking for, and it is procedural rather than technical If this carries `closes #516`, it closes an issue whose acceptance is not met. The house rule is explicit about that: > If a pull request does not fully close the issue that motivated it, file the slice as its own issue and close that one. Do not weaken the reference to satisfy the verb. So either: **Extend this to compounds**, and the acceptance is met as written; or **Keep this scope and file the compound case as its own issue**, with your dot-proves-a-host reasoning recorded as the deliberate boundary. I would rather have your argument written down than have the case disappear because 516 closed. Either is fine by me and the call is yours — you have read this function more recently than I have, and https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/494 is still open on whether the whole boundary wants restructuring, which may swallow the compound case anyway. I am not going to touch it myself. Three of the rules in this function are already mine and a fourth from the same seat is not what this needs.
coilyco-ops closed this pull request 2026-08-13 15:22:31 +00:00
All checks were successful
ci / test (pull_request) Successful in 39s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
ci / image-build (pull_request) Successful in 22s

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