diff --git a/docs/archive/2026-10-18-tight-item-lines/plan.md b/docs/archive/2026-10-18-tight-item-lines/plan.md
new file mode 100644
index 0000000..bd79dcc
--- /dev/null
+++ b/docs/archive/2026-10-18-tight-item-lines/plan.md
@@ -0,0 +1,134 @@
+# Blocks the block before them takes
+
+## Why
+
+A tight item writes each block on the line after the one before, and
+validation checks only a block right after a paragraph. A block after a
+nested list, a quote, or a footnote that ends in a paragraph is read back as
+that paragraph's lazy line, and a block after a table, a `
`-style HTML
+block, a definition, or a quote is read back inside it: `to_markdown`
+returns Markdown that reads as another tree, and Settle cannot tell that it
+should write the list loose.
+
+- Reported by Settle: a tight item holding a paragraph `a`, a tight list of
+ an item `b`, and a paragraph `c` is written `"- a\n - b\n c\n"`, where
+ `c` reads back as `b`'s lazy line.
+- Scope: every pair of adjacent blocks in a tight item that the line join
+ merges, and, in any container, indented code after indented code or a
+ footnote definition and any block after an HTML block its value leaves
+ open, which no source spells either. Validation refuses them; the
+ writer is unchanged.
+
+## What changes
+
+### Validation
+- `validation` › Shapes that cannot be written: modified — in a tight list
+ item, a block is refused after any block that takes the line written
+ after it, not only after a paragraph; in any container, an indented code
+ block is refused after an indented code block or a footnote definition,
+ and any block after an HTML block its value leaves open
+
+### Outside the specs
+- Settle (another repository), once this ships in a published release: bump
+ `markdown-syntax`; `save()` already writes loose the tight list a refusal's
+ path falls in, so a refused item is saved loose with no Settle code change.
+
+Specs:
+- `validation` (modified)
+
+## Out of scope
+- A block after a list whose first line reaches the list's last item's
+ content column (indented code, or an HTML block opening with spaces), in a
+ tight item or across a blank line — the source's marker width sets that
+ column, so parsed documents hold such pairs (`" - one\n\n two"`),
+ and refusing them would refuse documents the parser produces; it needs a
+ writer change, in its own plan.
+- A paragraph whose text reads as syntax where it is written, such as `(t)`
+ after a definition without a title — text the builder answers for, by the
+ rule closing `validation` › Shapes that cannot be written.
+- Writing such an item loose instead of refusing it — the serializer only
+ renders (`serialization` › Rendering only), and `tight` is part of the
+ tree a read-back compares.
+
+## Design
+
+### The rule
+
+The shapes are `validation` › Shapes that cannot be written, as the spec
+change states them: for each pair of adjacent blocks `left`, `right` in a
+container (blank lines skipped, as for adjacent lists), `right` is refused
+when `left` takes its first line, read from `left`'s kind and its last
+descendants by the parser's own checks. Three of those checks are not the
+obvious ones:
+
+- On a line after a nested container, the parser checks block starts
+ against the matched container (the outer item), not the open paragraph,
+ so an ordered list from 2, an empty item, and a lone-tag HTML block start
+ there: after a table and after a container ending in a paragraph, the
+ test is "starts no block where no paragraph is open", not "interrupts a
+ paragraph".
+- A line opening with a backtick or a tilde ends a quote's paragraph
+ instead of continuing it lazily (GH-19), so the descent records whether it
+ passed a quote or an alert.
+- An HTML block of an end-marker kind left open by its value runs to its
+ container's end, so in a parse it is always the last sibling.
+
+Every other left block ends where its own syntax or line does. The descent
+stops at a last `BlankLine` (a closed paragraph), at a nested empty item
+(the line is written short of its content column), and at fenced code,
+headings, directives, and HTML containers.
+
+The diagnostic's path is `right`'s, as for every shape among siblings, so
+Settle's `save()` writes loose the innermost tight list around it, the
+item's own list, which then writes the pair with a blank line between.
+
+### Architecture
+
+`validate_blocks` takes whether its container is a tight item and checks
+each pair through `validate_taken_block`, which replaces
+`validate_tight_item`. The tight table lives in `takes_next_line`, with
+`starts_outside_paragraph` for the matched-container start check and
+`ends_in_open_paragraph` for the descent. The descent follows only last
+children, and a block reached on one left block's descent is a last child
+and so is never another left block, so the walks stay linear in the tree.
+
+Parser helpers give the HTML kinds (`html_block_opens`,
+`html_block_ends_at_blank_line`, `html_block_left_open`); the serializer gives
+`written_opens_fence_like`, which writes the right block once.
+
+### Decisions
+- Refuse in validation — because validation is the only check that refuses
+ (`serialization` › Invalid documents are rejected) and Settle already
+ writes a refused tight list loose. Turned down: writing the item loose,
+ which changes `tight` silently.
+- A rule by kind, not a probe parse of the two blocks as written — because
+ validation judges shapes, and a probe writes and parses each pair at every
+ nesting level (quadratic in depth on untrusted trees, decision 0011).
+ Turned down: the source writer's probe (`starts_after_leaf`), which reads
+ the source's markers and needs the written first line.
+- Refuse only shapes no source spells — because validation runs before the
+ source writer too, and refusing a parsed document would leave an editor
+ unable to save a note it opened. Turned down: refusing indented code after
+ a list, which wide source markers spell.
+
+### Test scope
+
+Hand-built tight items for each row, each refused tight and read back when
+written loose; the blocks that start their own line after each row; and
+parsed tight items holding those shapes (an ordered list from 2, a lone tag,
+an empty item, indented code after a table, a fence-like paragraph after a
+quote, a quote ending in a blank line). The fixtures and generated read-back
+tests keep checking that parsed documents still write.
+
+## Tasks
+
+Release: the change ships as `fix` (a hand-built tree written wrongly is
+now refused). The Settle bump follows once a published release holds it.
+
+### 1. Validation
+- [x] 1.1 Each pair of the rule is refused and the nearby shapes accepted; verified by `tests/validate_regressions.rs` › `written_shapes` › `a_block_in_a_tight_item_is_not_taken_by_the_block_before_it`, `indented_code_is_not_taken_by_the_block_before_it`, and `no_block_follows_an_html_block_left_open`, naming `validation: Shapes that cannot be written`.
+ - Follows Design › The rule.
+- [x] 1.2 The reported tree is refused with the path of its last paragraph; verified by `node_paths` › `a_paragraph_after_a_nested_list_in_a_tight_item_names_the_paragraph`, the spec change's scenario.
+
+### 2. Integration
+- [x] 2.1 Every CI command in `CLAUDE.md` › Commands passes locally.
diff --git a/docs/specs/validation.md b/docs/specs/validation.md
index 174d45a..ef23d07 100644
--- a/docs/specs/validation.md
+++ b/docs/specs/validation.md
@@ -23,21 +23,45 @@ directive's.
### Requirement: Shapes that cannot be written
Validation SHALL reject exactly these shapes, each visible from the node, its
-children, its sibling blocks, how many containers enclose it, or whether it
-sits in a table cell or a directive label:
+children, its sibling blocks and the last blocks they end in, how many
+containers enclose it, or whether it sits in a table cell or a directive
+label:
- Block sequences: two adjacent `List`s in the same container written with
the same marker char; a list recording a delimiter of the other list kind is
- written with `-` when unordered and `.` when ordered.
-- In a tight list item, a block right after a `Paragraph` that cannot
- interrupt it, by the parser's own checks: a `Paragraph`, a `Definition`, an
- indented `CodeBlock`, a `Frontmatter`, a `Heading` written as a setext
- heading, an ordered `List` whose first item's number is not 1, a `List` whose first item
- has no blocks or that the serializer starts on a line after its bullet (a
- thematic break of the bullet's char, or content opening with one to three
- spaces or a tab), or an
- `HtmlBlock` whose first line opens no HTML block or opens one that only a
- blank line ends (a lone tag such as ``).
+ written with `-` when unordered and `.` when ordered. An indented
+ `CodeBlock` after an indented `CodeBlock` or a `FootnoteDefinition` in the
+ same container, blank lines between them or not; any block after an
+ `HtmlBlock` whose first line opens one that an end marker closes (a
+ comment, a raw tag such as `", "", ""] {
+ let document = document(vec![html_block(closed), paragraph(vec![text("a")])]);
+ assert!(valid(&document) && reads_back(&document), "{closed:?}");
+ }
+ assert!(valid(&parsed("- a\n\n