WORK-589
ID:WORK-589Status:done

Anchor-native presentation — reindent, highlight-match, and the coordinate frame

Anchoring makes nested targets easy for the first time — a class method, a key inside "scripts", a rule inside @media, a step under jobs:. Two existing attributes are defined in terms of lines= and stop making sense under an anchor, and one new attribute is needed because the old form re-couples the invocation to the coordinates the spec exists to decouple it from.

Small, and it is a prerequisite for two later items rather than a tail: WORK-590's byte-identical check has an ordering constraint against reindent, and WORK-591's hash normalization begins with it.

Priority:mediumComplexity:moderateMilestone:v0.37.0Source:SPEC-131
claude/nifty-ptolemy-80epot View source

Criteria completion

Criteria completion: 7 of 7 (100%) checked; history from Sep 23 to Sep 240%25%50%75%100%Sep 23Sep 24
Branches 4
History 3
  1. ab57f06
    • ☑ `reindent` strips the slice's common leading whitespace, defaulting on for `symbol` / `match` and off for `lines`, covered by a test on a nested target
    • ☑ `reindent=false` and `reindent=true` force either way
    • ☑ A dedented indentation-significant slice remains structurally valid, covered by a Python method and a YAML subtree
    • ☑ `linenumbers` and numeric `highlight` stay in file coordinates under an anchor
    • ☑ `highlight-match` accepts one or more regexes and highlights matching lines within the resolved slice
    • ☑ The docs state that numeric `highlight` under an anchor carries the coordinate exposure anchoring otherwise removes
    • ☑ `reindent` is applied after the resolved `[start, end]` is fixed, so it never shifts the coordinates `linenumbers` and `highlight` read
    by bjornolofandersson
  2. 45c53a2
    Created (ready)by bjornolofandersson
  3. d40fe65
    Content editedby Claude
    docs(plan): break the documentation-drift specs into v0.37.0

reindent (D16)

Strip the slice's common leading whitespace. Every nested target carries one or two levels of indentation it did not ask for and renders with a ragged left edge that wastes horizontal space a code block does not have.

Removing the common prefix preserves relative structure exactly, so the result stays valid in indentation-significant languages: a dedented Python method is a function, a dedented YAML subtree is that subtree rooted.

The default follows the addressing mode, for the same reason D9's does. An author writing lines="10-40" has seen the file and chosen those columns; changing how they render would be a silent visual change to all 23 existing invocations. An author writing symbol="…" never saw a column number — the resolver picked the region, so it owns presenting it legibly.

The coordinate frame stays (D13)

linenumbers and numeric highlight are currently defined in terms of lines=. Remove lines= and neither has a frame. The resolver already produces a [start, end] in file coordinates, so keep it: linenumbers continues to start at start, highlight continues to mean file lines. No new concept, no breakage, and the displayed numbers stay meaningful as a pointer back into the real file.

What changes is that a numeric highlight under an anchor is no longer something an author can write from knowledge. Hence highlight-match=: one or more regexes, each highlighting the lines they match within the resolved slice.

Numeric highlight stays legal and stays useful with lines=. Under an anchor it carries the old exposure, and the docs should say so plainly rather than forbidding it.

Acceptance Criteria

  • reindent strips the slice's common leading whitespace, defaulting on for symbol / match and off for lines, covered by a test on a nested target
  • reindent=false and reindent=true force either way
  • A dedented indentation-significant slice remains structurally valid, covered by a Python method and a YAML subtree
  • linenumbers and numeric highlight stay in file coordinates under an anchor
  • highlight-match accepts one or more regexes and highlights matching lines within the resolved slice
  • The docs state that numeric highlight under an anchor carries the coordinate exposure anchoring otherwise removes
  • reindent is applied after the resolved [start, end] is fixed, so it never shifts the coordinates linenumbers and highlight read

Approach

Keep reindent as a distinct post-resolution step with its own entry point, rather than folding it into extraction. WORK-590 must compare slices before it runs and WORK-591 must hash after it runs — both need to call the pipeline at a chosen point, which an inlined transform does not allow.

Blocked by

  • WORK-587 — there is no resolved slice to present without it

Notes

The ordering constraint is worth stating twice because it is easy to get backwards and produces a confusing failure in each direction:

  • WORK-590's codemod verifies a rewritten invocation produces a byte-identical slice. That comparison runs before reindent, or every nested target fails verification for a difference the codemod introduced.
  • WORK-591's hash applies reindent first, so that moving a function into a class — which shifts every line two columns without changing a character of content — does not fire the marker.

References

  • SPEC-131 — D13 (highlight / linenumbers keep file coordinates; highlight-match is the anchor-native form), D16 (reindent, its default, and the codemod interaction)
  • SPEC-134 — normalization step 1, which is this item's reindent
  • packages/runes/src/tags/snippet.ts — the schema carrying linenumbers and highlight, and their lines=-framed descriptions

Resolution

Completed: 2026-09-24

Branch: claude/v0-37-0-review-vqpl41 PR: refrakt-md/refrakt#647 (batched with WORK-587 and WORK-588)

What was done

  • packages/runes/src/lib/present.ts (new) — reindent, shouldReindent, highlightMatchLines, parseHighlightMatch, formatHighlight.
  • Wired into snippet-pipeline.ts after the resolved range is fixed, and into the file-ref drawer builder.
  • reindent and highlight-match attributes on both runes.

Notes

  • These are separate entry points on purpose, as this item's Approach requires. WORK-590's codemod compares slices before reindent or every nested target fails verification for a difference the codemod itself introduced; WORK-591's hash applies it first so that moving a function into a class does not fire the marker. An inlined transform would allow neither.
  • reindent does not guess a tab width. A slice mixing tabs and spaces has no common prefix and is returned unchanged — manufacturing one would change bytes the author did not ask to change. Pinned by a test.
  • The coordinate frame survives anchoring. An anchored slice now emits lines="start-end" from the resolved range, so linenumbers keeps starting at the real file line. highlight-match offsets are converted from slice coordinates into that same file frame before reaching the fence.
  • Defaults follow the addressing mode, so none of the existing line-addressed invocations change how they render — covered by a test asserting a lines= slice keeps its leading indentation.

Verification

4820 tests pass, 0 failures.