20 - the CommonMark link takes the try prefix too, and §11's rule names it
CI / gate (push) Successful in 29s
CI / publish (push) Has been skipped

This commit is contained in:
2026-09-21 21:07:54 +02:00
parent 6391928fb4
commit 97bf2440fd
4 changed files with 19 additions and 14 deletions
+9 -8
View File
@@ -307,14 +307,15 @@ someone spells it or pins it.
opener search stay whole: broken into named steps they drift from the algorithm being faithful is
the whole point of.
- A readable spelling tried ahead of a general one — a CommonMark block, the image, the pipe
table, a pipe cell — gives way with `undefined` for every shape it cannot spell, and fails only
where the general form fails on the same node; it takes the `try` prefix, so both arms read at
the call site (20). Refusing there refuses a document the general form spells, so a refusal the
general form does not share belongs in the general form or nowhere — save the nested list a
tight spelling would swallow, whose refusal the tight-versus-blank answer owns (`todo.md` 2b). A readable spelling that must spell its subtree
before it can give way — the list, whose thematic-break first line and blank lines exist only
spelled — hands that one walk to the general form instead: giving way after the walk walks
again at every level, doubling per level (4b).
table, a pipe cell, the CommonMark link — gives way with `undefined` for every shape it cannot
spell, and fails only where the general form fails on the same node; it takes the `try` prefix,
so both arms read at the call site (20). Refusing there refuses a document the general form
spells, so a refusal the general form does not share belongs in the general form or nowhere —
save the nested list a tight spelling would swallow, whose refusal the tight-versus-blank answer
owns (`todo.md` 2b). A readable spelling that must spell its subtree before it can give way —
the list, whose thematic-break first line and blank lines exist only spelled — hands that one
walk to the general form instead: giving way after the walk walks again at every level, doubling
per level (4b).
- Nothing recurses unbounded: the guards walk iteratively, and blocks, marks and JSON values — an
attribute's and a carried node's alike — are all held to 500 levels, so a deep document is a
`Result` rather than the stack overflow that waits near 2000. A level is one block-list
+2 -3
View File
@@ -258,7 +258,7 @@ function emitMarkedRun(nodes: readonly AdfNode[], mark: AdfMark, depth: number,
if (attributes === undefined) return success({ carry: range })
if (spelling.kind === 'code') return emitCodeSpan(nodes, depth, range, path)
if (spelling.kind === 'emphasis') return emitEmphasis(nodes, spelling.spelling, depth, range, context)
const link = spelling.kind === 'link' ? emitLink(nodes, mark, depth, range, context) : undefined
const link = spelling.kind === 'link' ? tryLink(nodes, mark, depth, range, context) : undefined
if (link !== undefined) return link
const inner = emitRun(nodes, depth + 1, index, { ...context, bracketed: true, spansLines: false })
if (!inner.ok) return inner
@@ -300,8 +300,7 @@ function needsPadding(text: string): boolean {
return text.startsWith(' ') && text.endsWith(' ') && /[^ ]/.test(text)
}
// `undefined` where the link takes the directive form the caller spells.
function emitLink(nodes: readonly AdfNode[], mark: AdfMark, depth: number, range: NodeRange, context: InlineContext): Result<Emission> | undefined {
function tryLink(nodes: readonly AdfNode[], mark: AdfMark, depth: number, range: NodeRange, context: InlineContext): Result<Emission> | undefined {
const href = linkHref(nodeAttrs(mark))
if (href === undefined) return success({ carry: range })
const opening = depth === 0 && range.first === 0 && context.openingLinkAsDirective
+5 -2
View File
@@ -933,8 +933,11 @@ The done `todo.md` items in full, as they were written. `todo.md` keeps a one-li
directive form shares — a walk, `codeBlockText`, `emitInlineLine` — so moving it out is the
second walk 4b removed, and they take the prefix alone. `tryRule` refuses nothing, so it
takes the narrower type as well, `string | undefined` through `readableText`, which is what
`tryImage` and `tryPipeTable` already return. §11's readable-spelling rule carries the
prefix, so the next spelling is named by the rule rather than by the six beside it.
`tryImage` and `tryPipeTable` already return. `emitLink` is the same channel outside the
six — the CommonMark link tried ahead of the inline directive form — so it takes the prefix
with them, and the comment naming its `undefined` arm goes with the rename. §11's
readable-spelling rule carries the prefix, so the next spelling is named by the rule rather
than by the seven beside it.
- [x] **28 — `emitLine`'s retry loop cannot spin (`0.2.0`).** `emit/inline-line.ts:67` is a
`for (;;)` that re-emits the line until every unspellable node has been carried, and its
termination rests on a comment: each pass carries at least one more node, or flips
+3 -1
View File
@@ -8,7 +8,9 @@ milestone. A done item shrinks to its title here; its full text moves to `todo-h
Start a session with: `Read AGENTS.md and todo.md, then do what todo.md's "Next session" says.`
1. `git fetch origin` first and read this file at `origin/main`, then branch off it, not the
worktree left behind: a checkout behind the remote reads a merged item as unchecked.
worktree left behind: a checkout behind the remote reads a merged item as unchecked. `tea pr
list` in the same breath — an open PR is a chunk already in flight whatever line 3 says, and
finishing it is the session.
2. The first unchecked item in shipping order, per AGENTS.md §15 — the order the Milestones line
states, which wins over where an item's bullet sits: a newly filed item is written beside the
one it came in with, not at its own place in the order. Where that item has no release, the