From fcc6640f6e8e9a49a33d9b75387cdc5c5260334f Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Sat, 10 Oct 2026 11:17:59 +0200 Subject: [PATCH] Answer architecture round 2: a list definitions end joins a set of ended lists, which a named endList fills and openedList reads --- docs/comprehension-history.md | 31 +++++++++++++++++++++++++++++++ src/markdown/parse/blocks.ts | 21 +++++++++++++++------ todo.md | 2 +- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/docs/comprehension-history.md b/docs/comprehension-history.md index 75d8773..5236b15 100644 --- a/docs/comprehension-history.md +++ b/docs/comprehension-history.md @@ -384,3 +384,34 @@ Inherited architect, decided by: - Shape, Locality: `src/markdown/parse/inline-content.ts:121` `readToken`: one pure tokenizer and one switch that applies tokens - Shape: `src/markdown/directive-syntax.ts:14` `ClaimedPrefix`: the directive read needs proof of its prefix, and the misnamed `opensConstruct` is gone - Locality: `src/markdown/emit/line-escaping.ts:112` `escapeClaims`: the escaper steps one character at a time while the reader steps by token, which only the `==` comment explains + +## 2026-10-10T09:16:56Z, PR #30 at 6182ba6, against c11aa91 + +Ruling: worse + +Fell: Locality. Under the floor of 7.0: Locality 5.63, so the same ruling counts as worse. + +| Seat | Navigation | Locality | Shape | Self-sufficiency | Overall | +|---|---|---|---|---|---| +| Mid A | same | worse | same | same | same | +| Inherited architect | better | worse | same | same | same | + +| Seat | Navigation | Locality | Shape | Self-sufficiency | Overall | +|---|---|---|---|---|---| +| Junior A | 7 | 5.5 | 6.5 | 5.5 | 6 | +| Mid A | 7 | 5.5 | 6.5 | 5.5 | 6 | +| Maintainability senior | 7 | 6 | 6.5 | 6 | 6 | +| Inherited architect | 6.5 | 5.5 | 6 | 6 | 6 | +| Mean | 6.88 | 5.63 | 6.38 | 5.75 | 6.00 | + +Mid A, decided by: + +- Locality: `src/markdown/parse/blocks.ts:79` `Walk.endedByDefinitions`: written in `closeLeaf` at `:469` and read in `openedList` at `:257`, never cleared, correct only by identity with `blocks.at(-1)`; `closeLeaf` takes on recording where definitions ended a list + +Inherited architect, decided by: + +- Locality: `src/markdown/parse/blocks.ts:79` `Walk.endedByDefinitions`: a never-reset field `closeLeaf` writes and `openedList` reads, right only by identity and by `openContainers` closing before it opens; reordering those steps breaks the split silently +- Locality: `src/markdown/parse/blocks.ts:432` `readLineBlock`: a second path that can find a paragraph emptied by definitions records nothing, which a reader must prove harmless by hand +- Navigation: `src/markdown/parse/blocks.ts:252` `openedList`: the comment names the exception, so a reader of two lists merged or not lands on the right unit +- Navigation: `README.md:242` the CommonMark exceptions bullet: each exception is named rather than counted by position +- Navigation: `CHANGELOG.md:5` `## Unreleased`: breaking entries come first, other changes last diff --git a/src/markdown/parse/blocks.ts b/src/markdown/parse/blocks.ts index a5abe84..c98a35d 100644 --- a/src/markdown/parse/blocks.ts +++ b/src/markdown/parse/blocks.ts @@ -75,8 +75,7 @@ type ContainerStack = { type Walk = ParsedBlocks & { claims: Claims - // The last block before a paragraph of link reference definitions alone, which ends a list as any block does. - endedByDefinitions: Block | undefined + endedLists: Set leaf: OpenLeaf | undefined leafOpeners: Map> position: SourcePosition @@ -92,7 +91,7 @@ export function parseBlocks(markdown: string, claims: Claims): ParsedBlocks { blocks: [], claims, definitions: new Map(), - endedByDefinitions: undefined, + endedLists: new Set(), leaf: undefined, leafOpeners: new Map(), position: { line: 1, offset: 0 }, @@ -249,16 +248,26 @@ function openContainer(walk: Walk, start: ContainerStart): void { walk.stack.push({ blocks, indentation: start.indentation, kind: 'item', list }) } -// An item opening after its list's last item closed, as an empty item a blank line ends does, continues that list, unless definitions ended it. +// An item opening after its list's last item closed, as an empty item a blank line ends does, continues that list. function openedList(walk: Walk, start: Extract): ListBlock { if (!start.fresh) return start.list const blocks = currentBlocks(walk) const previous = blocks.at(-1) - if ((previous?.kind === 'bulletList' || previous?.kind === 'orderedList') && previous !== walk.endedByDefinitions && continuesList(previous, start.list)) return previous + if (isList(previous) && !walk.endedLists.has(previous) && continuesList(previous, start.list)) return previous blocks.push(start.list) return start.list } +// A paragraph of link reference definitions alone leaves no block, yet ends the list before it as any block does. +function endList(walk: Walk): void { + const previous = currentBlocks(walk).at(-1) + if (isList(previous)) walk.endedLists.add(previous) +} + +function isList(block: Block | undefined): block is ListBlock { + return block?.kind === 'bulletList' || block?.kind === 'orderedList' +} + function closeContainers(walk: Walk, depth: number): void { closeLeaf(walk) for (const container of walk.stack.drop(depth)) { @@ -466,7 +475,7 @@ function closeLeaf(walk: Walk): void { if (leaf === undefined) return if (leaf.kind === 'paragraph') { const paragraph = takeParagraph(walk) - if (paragraph === undefined) walk.endedByDefinitions = currentBlocks(walk).at(-1) + if (paragraph === undefined) endList(walk) else currentBlocks(walk).push(bareTableFault(paragraph, walk.claims) ?? paragraph) return } diff --git a/todo.md b/todo.md index a59c61f..2579703 100644 --- a/todo.md +++ b/todo.md @@ -355,7 +355,7 @@ quadratic in a run of blanks inside one leaf: a paragraph of `a`, 80 000 spaces, Technical principle "One owner per value": the `Walk` record passes through twelve functions that mutate it and return `void`; `walk.leaf` alone is written in seven places, and `openedList` reads -the `endedByDefinitions` that `closeLeaf` leaves. `ContainerStack` in the +the `endedLists` that `closeLeaf` fills. `ContainerStack` in the same file shows the shape to follow. `inline-content.ts`'s `Scan` has the same shape: about fifteen functions write `pending`, `pieces`, `deactivatedBefore` and `openingSpellableLink` and return `void`, and `parseInlineContent` reads a flag `scanInline` leaves on it. The same shape recurs in