From bda394ea4e8810ebd2c8bc9409f884ec74fccb30 Mon Sep 17 00:00:00 2001 From: Ben Stull Date: Fri, 12 Jun 2026 00:16:57 -0700 Subject: [PATCH] F10 SLICE-3: remove superseded public renderAuthorship (salvaged into colorByAuthor) (#29) Co-Authored-By: Claude Opus 4.8 (1M context) --- src/trackChangesModel.ts | 33 -------------- test/trackChangesModel.test.ts | 78 +--------------------------------- 2 files changed, 1 insertion(+), 110 deletions(-) diff --git a/src/trackChangesModel.ts b/src/trackChangesModel.ts index 0f92c97..1c467b1 100644 --- a/src/trackChangesModel.ts +++ b/src/trackChangesModel.ts @@ -367,39 +367,6 @@ export function colorByAuthor( return sentinelsToSpans(render(injected)); } -/** - * Pure authorship render (INV-26/28): the CURRENT text with each F3-attributed - * span colored by author. Prose blocks get inline ``; - * code/mermaid fences stay ATOMIC (INV-27) — an overlapping span yields a - * block-level author badge, never inner sentinels. Deterministic. - */ -export function renderAuthorship( - currentText: string, - spans: AuthorSpan[], - opts: RenderOptions = {}, -): string { - const render = opts.render ?? defaultRender; - const safe = (src: string): string => { - try { - return render(src); - } catch (err) { - return chip(err instanceof Error ? err.message : String(err)); - } - }; - return splitBlocksWithRanges(currentText) - .map((b) => { - const overlapping = spans.filter((s) => s.end > b.start && s.start < b.end); - if (b.type !== "prose") { - const badge = authorBadge(new Set(overlapping.map((s) => s.author))); - const inner = safe(b.raw); - if (!badge) return `
${inner}
`; - return `
${badge.label}${inner}
`; - } - return `
${colorByAuthor(b.raw, b.start, overlapping, safe)}
`; - }) - .join("\n"); -} - /** Off-state body: the current buffer as plain markdown, no annotations (INV-33). */ export function renderPlain(currentText: string, opts: RenderOptions = {}): string { const render = opts.render ?? defaultRender; diff --git a/test/trackChangesModel.test.ts b/test/trackChangesModel.test.ts index 55c6ef5..5a2c306 100644 --- a/test/trackChangesModel.test.ts +++ b/test/trackChangesModel.test.ts @@ -1,5 +1,5 @@ import { describe, it, test, expect } from "vitest"; -import { splitBlocks, splitBlocksWithRanges, diffBlocks, renderTrackChanges, renderAuthorship, colorByAuthor, type AuthorSpan } from "../src/trackChangesModel"; +import { splitBlocks, splitBlocksWithRanges, diffBlocks, renderTrackChanges, colorByAuthor, type AuthorSpan } from "../src/trackChangesModel"; describe("splitBlocks", () => { it("splits prose paragraphs on blank lines, dropping empties", () => { @@ -159,82 +159,6 @@ describe("splitBlocksWithRanges — block offsets align with the source string", }); }); -describe("renderAuthorship", () => { - const spanAt = (text: string, sub: string, author: "claude" | "human"): AuthorSpan => { - const start = text.indexOf(sub); - return { start, end: start + sub.length, author }; - }; - - it("empty spans → plain render (no author wrappers)", () => { - const text = "# Hi\n\nplain paragraph.\n"; - const html = renderAuthorship(text, []); - expect(html).not.toContain("cw-by-claude"); - expect(html).not.toContain("cw-by-human"); - expect(html).toContain("plain paragraph."); - }); - - it("wraps a single Claude span inline", () => { - const text = "The cat sat on the mat.\n"; - const html = renderAuthorship(text, [spanAt(text, "cat sat", "claude")]); - expect(html).toContain('cat sat'); - }); - - it("marks two authors in one paragraph at exact boundaries", () => { - const text = "Alpha beta gamma.\n"; - const html = renderAuthorship(text, [ - spanAt(text, "Alpha", "human"), - spanAt(text, "gamma", "claude"), - ]); - expect(html).toContain('Alpha'); - expect(html).toContain('gamma'); - }); - - it("handles two ADJACENT spans (one's end == next's start) in order", () => { - const text = "ONETWO\n"; - const html = renderAuthorship(text, [ - { start: 0, end: 3, author: "human" }, // ONE - { start: 3, end: 6, author: "claude" }, // TWO - ]); - expect(html).toContain('ONETWO'); - }); - - it("clips a span to its block (does not bleed across blocks)", () => { - const text = "Para one.\n\nPara two.\n"; - const html = renderAuthorship(text, [{ start: 0, end: text.length, author: "claude" }]); - expect(html).toContain('Para one.'); - expect(html).toContain('Para two.'); - }); - - it("a code fence overlapping a span gets a block badge, NOT inner sentinels (atomic)", () => { - const text = "```js\nconst x = 1;\n```\n"; - const html = renderAuthorship(text, [{ start: 0, end: text.length, author: "claude" }]); - expect(html).toContain("cw-by-claude"); - expect(html).toContain("cw-badge"); - expect(html).not.toMatch(/[\uE000-\uE003]/); // no sentinel leaked - expect(html).toContain("const x = 1;"); - }); - - it("a mermaid fence authored by Claude renders as a diagram with a badge", () => { - const text = "```mermaid\ngraph TD; A-->B;\n```\n"; - const html = renderAuthorship(text, [{ start: 0, end: text.length, author: "claude" }]); - expect(html).toContain('pre class="mermaid"'); - expect(html).toContain("cw-by-claude"); - expect(html).toContain("cw-badge"); - }); - - it("never leaks a raw sentinel into prose output", () => { - const text = "Some mixed text here.\n"; - const html = renderAuthorship(text, [spanAt(text, "mixed", "claude")]); - expect(html).not.toMatch(/[\uE000-\uE003]/); - }); - - it("is deterministic", () => { - const text = "Stable input paragraph.\n"; - const spans: AuthorSpan[] = [spanAt(text, "input", "claude")]; - expect(renderAuthorship(text, spans)).toBe(renderAuthorship(text, spans)); - }); -}); - describe("colorByAuthor", () => { test("colorByAuthor wraps human-authored prose in cw-by-human spans", () => { const raw = "hello world";