WORK-588
ID:WORK-588Status:done

The remaining extents — dedent, section, paired, and the explicit terminators

WORK-587 makes brace-structured code addressable. This item makes everything else addressable, and closes D4's dead-end risk before anyone depends on the feature.

SPEC-131 D11 is the case: there are four structural families, not two, and the two this item adds are where every non-code target lives.

Priority:highComplexity:complexMilestone:v0.37.0Source:SPEC-131
claude/v0-37-0-review-vqpl41 View source

Criteria completion

Criteria completion: 15 of 15 (100%) checked; tracking started on Sep 24, no incremental history yet0%25%50%75%100%Sep 24Oct 11

Tracking started Sep 24 — check back for trends.

Branches 4
History 2
  1. 16cc31b
    Content editedby bjornolofandersson
  2. bad92a2
    Created (in-progress)by bjornolofandersson

Why paired is urgent rather than nice

It is the one gap that fails silently. Point auto at a Svelte file anchored on <script> and delimiter counting terminates at the first } closing a brace block at anchor depth — somewhere inside the script body. The slice balances, so WORK-587's self-check passes and the page renders a plausible wrong span. The self-check cannot catch it: the extent is wrong because the wrong family was used, not because the lexer misread anything.

LANG_MAP already ships markdoc, svelte, vue, html and jsx, so this is reachable today by anyone quoting those files.

The Markdown masker is its own budget line

For section and paired over Markdown the masker must blank fenced blocks and inline code spans — and on a docs site those fences frequently contain the very tokens being counted. site/content/runes/tabs.md:44 has {% tab %} in an inline code span. The pages most worth quoting with paired are exactly the ones full of fenced examples of the tags.

SPEC-131 says plainly: budget this separately from the C-family masker; it is not the same ~40 lines.

Three token shapes, and the table must distinguish them

  • Asymmetric, nestable — {% tabs %} / {% /tabs %}, <section> / </section>. Count depth.
  • Symmetric — a ``` fence. Cannot nest, so the first recurrence closes.
  • Self-closing — {% snippet /%}, <img>, <br>. There is no close, so a paired scan anchored on one would run to EOF. Detect and return one line.

until and through are two attributes on purpose

D12: until="^}" in code wants the terminator line in; until="^## " in Markdown wants it out. Either default is silently wrong half the time, on the attribute D4 designates as the escape hatch of last resort. Two attributes, each saying what it means.

Acceptance Criteria

  • extent accepts auto (default), dedent, section, and paired; until / through override all four
  • until excludes its matching line and through includes it; neither is inferred from the file or the strategy
  • An until / through that never matches refuses rather than returning the rest of the file
  • For Markdown, the masker also blanks fenced blocks and inline code spans, covered by a test anchoring past a ## heading and a {% %} tag that appear inside a fence
  • dedent expands tabs at a width taken from the language table
  • extent="dedent" is covered by tests against an indentation-structured fixture
  • extent="section" derives its terminator from the anchor's own level, covered by tests on a ### Markdown heading and a TOML table
  • extent="paired" balances nested same-name tokens, covered by a test extracting an outer {% tabs %} containing inner {% tab %} blocks
  • paired handles asymmetric, symmetric, and self-closing token shapes; a self-closing anchor returns one line rather than scanning to EOF
  • The balance self-check does not run for dedent, section, until or through, covered by a test extracting a prose Markdown section containing unbalanced brackets
  • paired self-checks on its own token stack
  • extent="auto" against a tag-paired file either refuses or is documented as unsupported — never renders a brace-terminated span from a tag-structured source
  • Heading/section shapes and token pairs come from the per-language table; a language absent from it gets no section / paired support rather than a guessed one
  • The engine is proven format-agnostic by tests on a brace-free format (Markdown or YAML) and a tag-paired one (Svelte or Markdoc)
  • snippet and file-ref doc pages document the new attributes, including the fallbacks

Approach

dedent is the simplest and was the prototype's first attempt at a universal rule — it failed there (a multi-line parameter list returns to the anchor's indent before the body opens, truncating roughly one TypeScript declaration in eight) and works well as a declared strategy. Do not be tempted to promote it.

Never infer strategy from the file (D5). Guessing dedent for .py and auto for .ts would be right most of the time and silently wrong the rest, reintroducing the failure mode the spec exists to remove. Table lookups for lexical facts; never for strategy.

Order within the item: until / through first (they are small and they are what every refusal message points at), then dedent, then the Markdown masker, then section and paired on top of it.

Blocked by

  • WORK-587 — the resolver these are strategies within

Notes

WORK-590's migration should not start before this lands — section and paired are what make the non-TypeScript half of site/content addressable at all.

References

  • SPEC-131 — steps 4–6, D4 (never a dead end), D5 (look up facts, never strategy), D11 (four families, and why both additions are earned), D12 (until vs through)
  • WORK-597 — the table these strategies read their shapes from
  • site/content/runes/tabs.md — the inline-code-span case the Markdown masker must survive

Resolution

Completed: 2026-09-24

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

What was done

  • dedent, section, paired and the explicit until / through terminators, in lib/anchor.ts.
  • The Markdown masker in lib/mask.ts — its own pass, selected by a language declaring fences / inlineCode rather than by name.
  • delimited added to the language table.
  • Doc prose on site/content/runes/snippet.md and file-ref.md.

Notes

  • delimited is the mechanism behind two separate criteria. It is a lexical fact — "does a ; or a matching } end a construct here" — not a strategy, so D5 holds: the engine still never guesses which extent to use. It lets auto refuse in Python and YAML instead of terminating on the next line, and it is what makes auto against a tag-paired file refuse rather than render a brace-terminated span from tag-structured source.
  • Fence markers stay visible; only the interior is masked. Blanking the markers would break both anchoring on a fence and the symmetric paired close. Worth preserving if this code is ever revisited.
  • section and paired read the masked lines, not the raw ones. That is the whole point of the Markdown pass — reading raw was the bug.
  • I checked this item's Markdown criterion off before it was true. Writing the test the criterion actually demands (## inside a fence, {% %} inside an inline span) failed immediately. Unchecked, implemented, re-checked. WORK-597's test asserting the masker ignores Markdown was updated rather than deleted, since it was correct when written.
  • paired self-checks on its own token stack: an unbalanced scan returns undefined and refuses. There is no separate delimiter balance for it, which is correct — D2 scopes that to auto.

Verification

4820 tests pass, 0 failures. Site content validates clean.