Skip to content

Pre-release fixes and 0.3.0 (#86, #83 follow-ups) - #91

Merged
dvejsada merged 4 commits into
mainfrom
claude/laughing-feynman-bsvdkq
Sep 29, 2026
Merged

dvejsada merged 4 commits into
mainfrom
claude/laughing-feynman-bsvdkq

Conversation

@dvejsada

@dvejsada dvejsada commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Closes #86.

These are the last fixes before 0.3.0, plus the version bump. Each change was implemented in its own worktree by a subagent, then reviewed, re-verified and merged here. A final review then led to one more fix.

1. A nested item's unclosed fence keeps its blank lines (#86)

Cause: in parser._scan_list, take a continuation line of an item nested on its parent's first line (- 1. z then a). It set paragraph, the flag for the current item's own open paragraph. A following sibling, ` 2. ```, then counted as a marker that may not interrupt that paragraph, so it was read as text. The outer scan never saw the item or its fence, and the blank line after the unclosed fence fell out of the enclosing item.

Fix: nine lines. Such a continuation line no longer claims the paragraph as the item's own. * 2. z\na\n 1. ```\n\n now round-trips.

Tests: 10 parametrized shapes, a round-trip test and an interruption-control test. They fail on main.

Verification against main:

  • A cmark-gfm structural oracle over 30k documents found no change in block structure.
  • A placeholder-count and round-trip corpus of 340k documents found no new problem and fixed 1 round-trip failure.
  • The final review's crafted sweep of 668k documents, compared against main and cmark-gfm, found 0 regressions and 483 newly fixed structures.
  • The line fuzz is clean, and spec-corpus diagnostics are identical to main.

2. #83 follow-ups

Line numbers. A custom field written with spaces around its key (' tax ': ...) is now reported on its own line.

  • The validator looks the key up as written (Locator.children). What is read into the model is unchanged.
  • A field merged into a party (<<) has no key of its own, and the model reads merged fields first. The final review found that the pairing then gave a merged field a padded key's line.
  • The source map now records a mapping's merge (positions.MERGE). Where a party merges keys in, a label that several fields share is looked up by its label, as on main.

Tests:

  • a padded key;
  • a padded key and a plain key together;
  • a padded field name that stays ignored;
  • unchanged lines for plain keys and the list form;
  • a merged field next to a padded key.

README: a party key named custom_fields is reserved for the list form. The paragraph is reflowed.

Cleanup: removes w_mn.log, a stray fuzzing log that #72 committed.

3. Prepare release 0.3.0

__version__ and the README's validator_version example become 0.3.0. The LegalDown specification version stays at 0.2 everywhere: SPEC_VERSION, legaldown_spec, "Targets specification v0.2", CONFORMANCE and CI.

Release notes for the GitHub release are drafted separately. They are not in the repository, and the final review's corrections are applied to them.

Verification

The full suite passes (1942 passed, 40 skipped), and ruff is clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_012pWb8FGHgaM3ZWbzsPiKsk

…ed custom_fields key (#83)

A party key with surrounding spaces is read stripped as a custom field,
but the source map records it as written, so its diagnostics fell back to
the party's first line. The validator now looks the path up by the key as
written (Locator.children), the nth field of a label being the nth key
that strips to it. What is read into the model is unchanged.

README: a party key named custom_fields is the list form's, never a
custom field.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012pWb8FGHgaM3ZWbzsPiKsk
A continuation line of an item nested on its parent's first line (`- 1. z`
and `     a`) set `paragraph` in `_scan_list`, the flag for the current
item's own open paragraph. A following `  2. ```` was then read as text of
that paragraph, since `2.` may not interrupt one: the scan never saw the
item or its fence, so the blank lines after the unclosed fence fell out of
the enclosing item and the code block lost its trailing "\n" (only when an
earlier sibling had a continuation line). The paragraph belongs to the
nested item, so the line does not set `paragraph`; the sibling starts an
item as it does after no continuation line. Parse then agrees with
cmark-gfm on a body where a list wrongly swallowed the setext heading
after it, and `* 2. z\na\n  1. ```` round-trips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012pWb8FGHgaM3ZWbzsPiKsk
Bump __version__ to 0.3.0 (the single source of truth, read by
pyproject.toml) and the validator_version in the README's JSON example.
Specification-version references (0.2) are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012pWb8FGHgaM3ZWbzsPiKsk
A custom field merged into a party (<<) has no key of its own, and the
model reads merged fields first: pairing the nth field with the nth key
that strips to its label then gave a merged field a padded key's line.
The source map records a mapping's merge (positions.MERGE), and where a
party merges keys in, a label several fields share is looked up by the
label, as before the padded-key change. README reflowed; w_mn.log, a
stray fuzzing log committed in #72, removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012pWb8FGHgaM3ZWbzsPiKsk
@dvejsada
dvejsada merged commit 9864ad8 into main Sep 29, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parser: an unclosed fence ending a nested item keeps its trailing blank line only if no earlier sibling item had a continuation line

2 participants