~bigbes/sr-ht-spec · parade

main · last commit 18 hours ago · 8tmadfpi

← Back to the parade

spec-by6.3.5 Port review UI to a line-numbered unified prose diff Past Stand

status: closed P2 feature
bd reopen spec-by6.3.5
Created byEugene Blikh
Ownerbigbes@gmail.com
Created2026-07-25T11:40:01Z
Updated2026-08-05T01:11:47Z
Closed2026-08-05T01:11:47Z
Description
Replace the block-card review renderer with a real unified diff: line-numbered gutter, drag-select a line range, comment composer inline. Owner reviewed the card version against a live proposal and rejected it — labels ('ADDED PARAGRAPH') outweighed content on every row, every block carried identical chrome, and on a new file the whole page is green so the cards add noise and no signal. Split view was considered and dropped: prose lines are long and unified reads better for reflowed text. Approved prototype: https://claude.ai/code/artifact/a45e45cb-16b5-42ec-8108-84767ef9f465
Design
SELECTION IS BY LINE, ANCHORING IS BY BLOCK. Lines are what the cursor lands on; block hashes are what survive a reflow. The web layer maps a selected line range to its enclosing prosediff block and stores the existing core.CommentAnchor unchanged. service/, db/ and core/ do not move. The composer states what it will anchor to, so the indirection is visible rather than magic.

THE BLOCKING PROBLEM — word marks cannot be placed on a line for free.
prosediff.Span is {Op, Text, Space} with no source offsets, and Tokenize
deliberately drops whitespace ('\n' and ' ' both collapse to Space=true) —
which is exactly what makes a rewrap invisible to the differ. So for a
ChangeModify block there is no stored answer to 'which line did this word
change on'.

Recoverable, not free: the span script consumes the old token sequence in order
(Equal+Delete) and the new one (Equal+Insert). Re-tokenize each source line of
Block.Lines, walk the script, and split a span where it crosses a line
boundary. Needs a mapper of roughly 100 lines plus tests. Equal/Insert/Delete
blocks need none of this — their lines map 1:1 and carry exact numbers.

FALLBACK IF THE MAPPER IS NOT WANTED: render a modified block as a paired
old/new region labelled by line RANGE rather than per line, keeping the word
marks. Honest and much smaller, but does not match the approved prototype.

GUTTER DETAILS SETTLED IN REVIEW: one shared rail ground for both number
tracks with a single hairline against the content (a border per cell drew a
cage); one --row-lh shared by gutter and prose so numerals sit on the text
baseline rather than floating; 34px tracks; the add/delete tint starts at the
sign column so the gutter never looks part of the change.

HEADING PATH: no per-hunk breadcrumb. It restated headings visible a few rows
above, always so on a new file. Replaced by one sticky section readout that
appears only once its heading has scrolled past. The path stays in the composer
and in each thread's anchor note, where the heading is usually off screen.
Acceptance criteria
A reviewer drags across line numbers, comments, and the thread stores an anchor identical to the one the block-card UI would have stored. Word-level marks still appear inside a modified paragraph. Unchanged lines render as context and collapse. An outdated comment still appears and is never attached to a neighbouring block.

Depends on

  • spec-by6.3 — Phase 5b: inline comments on proposals parent-child closed

Depended on by

Nothing depends on this issue.

Prerequisite chain — everything this waits on, transitively

  • spec-by6.3 — Phase 5b: inline comments on proposals parent-child closed
  • spec-by6 — Phase 5: comments, webhooks, mutations, vector search parent-child open
  • spec-3vz — Phase 4: review plane — approve/reject in a browser blocks closed
  • spec-ejq — spec.sr.ht — reviewable document storage for humans and agents parent-child open
  • spec-zqb — Phase 3: write plane — agents propose blocks closed

No comments.

Close reason

Closed
  • Eugene Blikh added under epic spec-by6.3 · 2026-07-25T14:40:01Z
  • Eugene Blikh created the issue · 2026-07-25T14:40:01Z
  • Eugene Blikh closed the issue · 2026-08-05T04:11:46Z
    Closed
Stored rows — what this pane was built from, as read
issues 1 row
id spec-by6.3.5
content_hash ad5850f9dfeb790caa01e085716a402bd3da5888d2d63e1bb407db8b8a422d79
title Port review UI to a line-numbered unified prose diff
description Replace the block-card review renderer with a real unified diff: line-numbered gutter, drag-select a line range, comment composer inline. Owner reviewed the card version against a live proposal and rejected it — labels ('ADDED PARAGRAPH') outweighed content on every row, every block carried identical chrome, and on a new file the whole page is green so the cards add noise and no signal. Split view was considered and dropped: prose lines are long and unified reads better for reflowed text. Approved prototype: https://claude.ai/code/artifact/a45e45cb-16b5-42ec-8108-84767ef9f465
design SELECTION IS BY LINE, ANCHORING IS BY BLOCK. Lines are what the cursor lands on; block hashes are what survive a reflow. The web layer maps a selected line range to its enclosing prosediff block and stores the existing core.CommentAnchor unchanged. service/, db/ and core/ do not move. The composer states what it will anchor to, so the indirection is visible rather than magic. THE BLOCKING PROBLEM — word marks cannot be placed on a line for free. prosediff.Span is {Op, Text, Space} with no source offsets, and Tokenize deliberately drops whitespace ('\n' and ' ' both collapse to Space=true) — which is exactly what makes a rewrap invisible to the differ. So for a ChangeModify block there is no stored answer to 'which line did this word change on'. Recoverable, not free: the span script consumes the old token sequence in order (Equal+Delete) and the new one (Equal+Insert). Re-tokenize each source line of Block.Lines, walk the script, and split a span where it crosses a line boundary. Needs a mapper of roughly 100 lines plus tests. Equal/Insert/Delete blocks need none of this — their lines map 1:1 and carry exact numbers. FALLBACK IF THE MAPPER IS NOT WANTED: render a modified block as a paired old/new region labelled by line RANGE rather than per line, keeping the word marks. Honest and much smaller, but does not match the approved prototype. GUTTER DETAILS SETTLED IN REVIEW: one shared rail ground for both number tracks with a single hairline against the content (a border per cell drew a cage); one --row-lh shared by gutter and prose so numerals sit on the text baseline rather than floating; 34px tracks; the add/delete tint starts at the sign column so the gutter never looks part of the change. HEADING PATH: no per-hunk breadcrumb. It restated headings visible a few rows above, always so on a new file. Replaced by one sticky section readout that appears only once its heading has scrolled past. The path stays in the composer and in each thread's anchor note, where the heading is usually off screen.
acceptance_criteria A reviewer drags across line numbers, comments, and the thread stores an anchor identical to the one the block-card UI would have stored. Word-level marks still appear inside a modified paragraph. Unchanged lines render as context and collapse. An outdated comment still appears and is never attached to a neighbouring block.
notes
status closed
priority 2
issue_type feature
assignee NULL
estimated_minutes NULL
created_at 2026-07-25T11:40:01Z
created_by Eugene Blikh
owner bigbes@gmail.com
updated_at 2026-08-05T01:11:47Z
closed_at 2026-08-05T01:11:47Z
closed_by_session
external_ref NULL
spec_id
compaction_level 0
compacted_at NULL
compacted_at_commit NULL
original_size NULL
sender
ephemeral 0
wisp_type
pinned 0
is_template 0
mol_type
work_type
source_system
metadata �{}
source_repo
close_reason Closed
event_kind
actor
target
payload
await_type
await_id
timeout_ns 0
waiters
hook_bead
role_bead
agent_state
last_activity NULL
role_type
rig
due_at NULL
defer_until NULL
no_history 0
started_at NULL
is_blocked 0
dependencies 1 row
id ce808c5f-ccd6-50c3-ba24-422984df8fa6
issue_id spec-by6.3.5
type parent-child
created_at 2026-07-25T14:40:01Z
created_by Eugene Blikh
metadata �{}
thread_id
depends_on_issue_id spec-by6.3
depends_on_wisp_id NULL
depends_on_external NULL
events 2 rows
id 019f9913-3831-7bd7-8876-d352b2460c79
issue_id spec-by6.3.5
event_type created
actor Eugene Blikh
old_value
new_value
comment NULL
created_at 2026-07-25T14:40:01Z
id 019fcf79-fe91-74f9-aa65-e68d2fe89309
issue_id spec-by6.3.5
event_type closed
actor Eugene Blikh
old_value
new_value Closed
comment NULL
created_at 2026-08-05T04:11:46Z