test(mentions): enumerate every position rather than reason about the rule #513

Merged
coilyco-ops merged 1 commit from qa/enumerate-the-mention-positions into main 2026-08-13 14:57:02 +00:00
Member

Five fixes reached resolveMentions today. Links, Discord markup, dotted identifiers, code spans, and a prose boundary still in review. Each was correct about the position it was shown, and each was found by somebody hitting the next one in a member's reply.

This enumerates positions instead of reasoning about the rule. Two replies a member actually receives, taken token by token, nineteen rows hand-classified:

  • every label and path segment of a link
  • the same address with no scheme, which urlSpan does not cover
  • the disclosure receipt, which rides on every tool-using turn
  • an inline command and a fenced block
  • Discord markup, where the inner text is an id or an emoji name
  • prose with emphasis, quotation, a comma, a full stop, and brackets around the name

Hand-classified, deliberately

Deriving the expected answer from the span logic would grade the implementation against itself. The why on each row is the reason a human gave, so a failure says "tool name in a code span" rather than "row 8".

Two assertions per row, not one

A name that must not resolve must also leave the text byte-identical. A rewrite without a ping still breaks the address, and separating the two is what makes a failing row diagnostic — it distinguishes "the guard stopped working" from "the guard fired but the rewrite happened anyway".

Checked against the fix in review, not only against main

main            19/19 pass
main + PR 498   19/19 pass

So this can land now without waiting on #498, and it will guard 498 when that merges.

That check exists because of #506, where a test of mine went stale during review and reddened main. A test written against today's behaviour has to be run against every branch about to change that behaviour, not just against main at authoring time.

Mutation checked

Dropping inline code spans while keeping fenced ones:

--- FAIL: TestEveryPositionResolvesOrDoesNot
    command in a code span: name "eco" in "run `eco status` to check" resolved=true, want false
    command in a code span: name "status" in "run `eco status` to check" resolved=true, want false

That is the shape this is for: a rule narrowed in one place, still passing every existing test, failing here with the position named.

One position deliberately absent

eco as the first label of a schemeless hostSee eco-app.coilysiren.me/jobs — still resolves on main and under 498. I have reported it on Kai's #468 rather than asserting it here, because it is a live defect and this file should stay green.

Adding that row is the right first move for whoever fixes it: it fails today, and the other eighteen prove the fix did not cost anything else.

Test-only. No production change.

Refs #486

**Five fixes reached `resolveMentions` today.** Links, Discord markup, dotted identifiers, code spans, and a prose boundary still in review. Each was correct about the position it was shown, and **each was found by somebody hitting the next one in a member's reply.** This enumerates positions instead of reasoning about the rule. Two replies a member actually receives, taken token by token, nineteen rows hand-classified: - every label and path segment of a link - the same address **with no scheme**, which `urlSpan` does not cover - the disclosure receipt, which rides on every tool-using turn - an inline command and a fenced block - Discord markup, where the inner text is an id or an emoji name - prose with emphasis, quotation, a comma, a full stop, and brackets around the name ## Hand-classified, deliberately Deriving the expected answer from the span logic would grade the implementation against itself. The `why` on each row is the reason a human gave, so a failure says *"tool name in a code span"* rather than *"row 8"*. ## Two assertions per row, not one A name that must not resolve must **also leave the text byte-identical**. A rewrite without a ping still breaks the address, and separating the two is what makes a failing row diagnostic — it distinguishes "the guard stopped working" from "the guard fired but the rewrite happened anyway". ## Checked against the fix in review, not only against main ``` main 19/19 pass main + PR 498 19/19 pass ``` So this can land now without waiting on https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/pulls/498, and it will guard 498 when that merges. **That check exists because of https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/506**, where a test of mine went stale during review and reddened `main`. A test written against today's behaviour has to be run against every branch about to change that behaviour, not just against `main` at authoring time. ## Mutation checked Dropping inline code spans while keeping fenced ones: ``` --- FAIL: TestEveryPositionResolvesOrDoesNot command in a code span: name "eco" in "run `eco status` to check" resolved=true, want false command in a code span: name "status" in "run `eco status` to check" resolved=true, want false ``` That is the shape this is for: a rule narrowed in one place, still passing every existing test, failing here with the position named. ## One position deliberately absent `eco` as the **first label of a schemeless host** — `See eco-app.coilysiren.me/jobs` — still resolves on `main` and under 498. I have reported it on Kai's https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/468 rather than asserting it here, because it is a live defect and this file should stay green. Adding that row is the right first move for whoever fixes it: it fails today, and the other eighteen prove the fix did not cost anything else. Test-only. No production change. Refs https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/486
test(mentions): enumerate every position rather than reason about the rule
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
ebee7a22be
Five fixes reached resolveMentions today. Links, Discord markup, dotted
identifiers, code spans, and a prose boundary still in review. Each was correct
about the position it was shown, and each was found by somebody hitting the next
one in a reply.

This is the same two replies a member actually receives, taken token by token,
with every position hand-classified. Nineteen rows: each label and segment of a
link, the same address with no scheme, the receipt, an inline and a fenced
command, Discord markup, and prose with emphasis, quotation, a comma, a full
stop and brackets around it.

Hand-classified rather than derived, because deriving the answer from the span
logic would grade the implementation against itself.

A name that must not resolve must also leave the text byte-identical. A rewrite
without a ping still breaks the address, and separating the two is what makes
the row diagnostic rather than a bare pass.

Checked against the fix in review as well as main. Both pass, so this can land
without waiting on 498 and will guard it when it merges. That check is the
lesson from 506, where a test of mine went stale during review and reddened
main.

Mutation checked: dropping inline code spans while keeping fenced ones fails
two rows and names both.

Refs sirens-echo#486

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