fix: separate raised citation markers with a space, not a comma #23

Merged
adrianbonpin merged 1 commits from fix/space-between-citations into prod 2026-10-07 08:24:10 +00:00
4 changed files with 12 additions and 9 deletions
Showing only changes of commit 7caab85cb5 - Show all commits
+1 -1
View File
@@ -302,7 +302,7 @@ Footnotes deserve a note of their own, because the window cannot draw them. Vici
In a sentence the marker is raised, so a claim resting on a search result reads as `rain is likely¹` rather than with the brackets at full size. It is a Unicode superscript digit rather than a `<sup>` tag, because a link label is plain text that nothing downstream can break, and a digit is raised by design in every font. The entry under the answer keeps the plain number, `[1] Rain in Cebu`, where being able to scan a list matters more than the convention. In a sentence the marker is raised, so a claim resting on a search result reads as `rain is likely¹` rather than with the brackets at full size. It is a Unicode superscript digit rather than a `<sup>` tag, because a link label is plain text that nothing downstream can break, and a digit is raised by design in every font. The entry under the answer keeps the plain number, `[1] Rain in Cebu`, where being able to scan a list matters more than the convention.
Markers the model wrote touching are separated as they are drawn, because `¹²` reads as twelve, or as twenty one, and either way as one number. The prompt asks for exactly that touching shape, so `[1][2]` and the same numbers written apart both arrive as `¹, ²`. Markers the model wrote touching are separated as they are drawn, because `¹²` reads as twelve, or as twenty one, and either way as one number. The prompt asks for exactly that touching shape, so `[1][2]` and the same numbers written apart both arrive as two raised digits with a space between them. A space rather than a comma: a comma sits at the baseline, so between raised digits it drops away from them and reads as a stray mark.
Numbers are handed out where the tools run, once per turn, and printed in the tool result the model reads. So `[3]` means one page for the model and for the reader, three searches in one turn do not each start again at `1`, and a page found by a search and read again later keeps the number it already had. A marker stays as written unless every number in it is a source with a destination this window should open: half a link reads as a citation that works, and a `javascript:` address out of a search result is a real vulnerability rather than a rendering quirk. Numbers are handed out where the tools run, once per turn, and printed in the tool result the model reads. So `[3]` means one page for the model and for the reader, three searches in one turn do not each start again at `1`, and a page found by a search and read again later keeps the number it already had. A marker stays as written unless every number in it is a source with a destination this window should open: half a link reads as a citation that works, and a `javascript:` address out of a search result is a real vulnerability rather than a rendering quirk.
@@ -163,9 +163,10 @@ The pass follows the rules the rest of the pipeline already follows.
machinery the maths pass uses. A `[1]` inside a snippet is text. machinery the maths pass uses. A `[1]` inside a snippet is text.
- **`[n]`, `[^n]`, comma lists, and runs.** `[1, 3]` is two sources inside one - **`[n]`, `[^n]`, comma lists, and runs.** `[1, 3]` is two sources inside one
marker, and `[1][2]` is two markers written touching. Both are drawn as raised marker, and `[1][2]` is two markers written touching. Both are drawn as raised
digits separated by a comma, because `¹²` reads as a single number and leaves the digits separated by a space, because `¹²` reads as a single number and leaves the
reader no way to tell where one citation ends, which is a defect the first version reader no way to tell where one citation ends, which is a defect the first version
of this shipped with. of this shipped with. A space rather than a comma, because a comma sits at the
baseline and so drops away from digits that are raised above it.
- **All or nothing.** A marker is linked only when every index it names is a - **All or nothing.** A marker is linked only when every index it names is a
known source. `[1, 9]` where 9 was never seen stays exactly as written, rather known source. `[1, 9]` where 9 was never seen stays exactly as written, rather
than becoming half a link. than becoming half a link.
+4 -4
View File
@@ -127,10 +127,10 @@ describe("linkCitations", () => {
expect(linkCitations("Rain [^1].", sources).text).toBe("Rain [¹](https://first.example)."); expect(linkCitations("Rain [^1].", sources).text).toBe("Rain [¹](https://first.example).");
}); });
it("links a list of markers and keeps the comma", () => { it("separates markers written as one list", () => {
const result = linkCitations("Both [1, 3] agree.", sources); const result = linkCitations("Both [1, 3] agree.", sources);
expect(result.text).toBe("Both [¹](https://first.example), [³](https://third.example) agree."); expect(result.text).toBe("Both [¹](https://first.example) [³](https://third.example) agree.");
expect([...result.cited].sort()).toEqual([1, 3]); expect([...result.cited].sort()).toEqual([1, 3]);
}); });
@@ -148,13 +148,13 @@ describe("linkCitations", () => {
// says it is two sources, or where the first one stops and the second begins. // says it is two sources, or where the first one stops and the second begins.
const result = linkCitations("Both [1][3] agree.", sources); const result = linkCitations("Both [1][3] agree.", sources);
expect(result.text).toBe("Both [¹](https://first.example), [³](https://third.example) agree."); expect(result.text).toBe("Both [¹](https://first.example) [³](https://third.example) agree.");
expect([...result.cited].sort()).toEqual([1, 3]); expect([...result.cited].sort()).toEqual([1, 3]);
}); });
it("treats a space between two markers the same way", () => { it("treats a space between two markers the same way", () => {
expect(linkCitations("Both [1] [3] agree.", sources).text).toBe( expect(linkCitations("Both [1] [3] agree.", sources).text).toBe(
"Both [¹](https://first.example), [³](https://third.example) agree.", "Both [¹](https://first.example) [³](https://third.example) agree.",
); );
}); });
+4 -2
View File
@@ -228,9 +228,11 @@ export function linkCitations(text: string, sources: Source[]): CitationResult {
} }
for (const index of wanted) cited.add(index); for (const index of wanted) cited.add(index);
// Separated even when the model wrote them touching: `¹, ²` is two citations, // Separated even when the model wrote them touching: `¹ ²` is two citations,
// where `¹²` is a number, and the reader has no way to tell it from a real one. // where `¹²` is a number, and the reader has no way to tell it from a real one.
return links.join(", "); // A space rather than a comma, which sits at the baseline and so drops away from
// digits that are raised above it.
return links.join(" ");
}), }),
); );