Skip to content

TDD 0055: markdown section/bullet parser unification (md.sh)#143

Merged
cahenesy merged 2 commits into
masterfrom
docs/design/markdown-parser-unification-0055
Jun 11, 2026
Merged

TDD 0055: markdown section/bullet parser unification (md.sh)#143
cahenesy merged 2 commits into
masterfrom
docs/design/markdown-parser-unification-0055

Conversation

@cahenesy

Copy link
Copy Markdown
Owner

Design PR (gate = your merge). One new TDD, Status: draft. The deferred md-section follow-up to 0049, from the consolidated scripts audit.

What & why

One new scripts/lib/md.sh single-sources the markdown-structure parsers and folds the bugs living in them. PRD unchanged (0aa1e28); gap-closure, same category as 0048–0054.

  • md_section_body <file> <heading> — fence-aware (``` and ~~~) in-section walk, rc-checked; callers layer their own predicate.
  • md_bullet_path_of_line <bullet-line> — the shared per-bullet path op (0049's annotation-robust algorithm), reused by md_bullet_path and the Expected-diff callers (count/exception stay caller-side).
  • md_bullet_path <file> <heading> [mode]md_section_body | /^- / | md_bullet_path_of_line; rc-propagating.

Routes 4 section-scan sites (plan-classifier, tdd-lint ×2, gates) + the ## Expected diff size path extraction + 0049's tl_extract_touched_paths through md.sh.

Folds: reuse #11 (plan-classifier.sh was the non-fence-aware copy → classifier-misroute), #12 (the un-cross-checked Expected-diff twin); bugs A21 (~~~ fences ignored), A23 (count vs extract anchor mismatch), A4 (gawk fatal exit 2 collides with the missing-section exit 2), L-005 (tl_extract_touched_paths swallows awk's exit code → spurious structural-finding(a)). The L-005 rc now propagates end-to-end through the delegation wrappers (split-declared captures dodge the local x="$(…)" rc mask) to _rework_pre_pass, which routes a parse failure away from structural-finding(a).

Build ordering (declared dependency)

Builds LAST: after 0049's impl (PR #142, which lands touched-files.sh) and after the 0050–0054 stack (shares gates.sh/tdd-lint.sh). Nothing stacks on 0055.

Design gate

  • Mechanical: tl_lint rc=0; --bounds rc=0; body 265/500; 8 files, no exception.
  • Independent critique (design-reviewer, sonnet): first pass DESIGN_REVIEW: BLOCK on two real gaps it caught — (1) md_bullet_path couldn't serve the count/exception Expected-diff callers; (2) the L-005 rc would be masked by local x="$(…)" before reaching the membership check. Both fixed (shared md_bullet_path_of_line; explicit split-declared rc propagation) plus the minors (count fence walk migrated; A4 sequencing; advisory _coverage_inscope_reqs carve-out). Re-review: DESIGN_REVIEW: PASS.
  • ADR evaluation: zero new ADRs; ADR 0006 governs and is respected.

Open assumptions & waivers

  • authoring against unmerged 0049 interface — resolved: 0049's design (TDD 0049: Touched-files extractor — single source of truth + annotation-robust #140) locks the tl_extract_touched_paths interface; 0055 declares the 0049-impl build-dependency and builds after build/20260610 202343/0049 touched files extractor unify and harden #142.
  • md_section_body must preserve each caller's in-section predicate — resolved: it emits raw fence-aware in-section lines; each caller keeps its own classify/row/column logic.
  • honoring ~~~ fences changes behavior — resolved: the ```-only parsers mis-handle ~~~ (the bug); honoring it is the fix, regression-pinned.
  • L-005 awk-rc check semantics — resolved: non-zero awk → rc 2 + stderr (never silent empty), so parse-fail is distinguishable from a genuinely-empty section.
  • touched-files delegate must not change output / break the 0049 cross-check — resolved: tl_extract_touched_paths keeps name/signature/output; the 0049 3-way agreement test still passes (Verification pins it).

🤖 Generated with Claude Code

Deferred follow-up to 0049 (from the consolidated scripts audit). One new
scripts/lib/md.sh single-sources the markdown-structure parsers and folds the
bugs living in them. PRD unchanged (0aa1e28); gap-closure, same category as
0048-0054.

- md_section_body <file> <heading> — fence-aware (``` AND ~~~) in-section walk,
  rc-checked; callers layer their own predicate.
- md_bullet_path_of_line <bullet-line> — the shared per-bullet PATH op (0049
  annotation-robust algorithm), reused by md_bullet_path AND the Expected-diff
  callers (count/exc stay caller-side).
- md_bullet_path <file> <heading> [mode] — md_section_body | /^- / |
  md_bullet_path_of_line; rc-propagating.

Migrates 4 section-scan sites (plan-classifier, tdd-lint x2, gates) + the
Expected-diff path extraction (gates _rework_file_declared_bound, tdd-lint
check_per_file_diff_bound) + 0049 tl_extract_touched_paths onto md.sh.

Folds: reuse #11 (section scan; plan-classifier was the non-fence-aware copy =
classifier-misroute bug), #12 (the un-cross-checked Expected-diff twin of the
Touched-files pair); bug A21 (~~~ fences ignored), A23 (count vs extract bullet
anchor mismatch), A4 (gawk fatal exit-2 == missing-section exit-2 collision),
L-005 (tl_extract_touched_paths swallows awk's exit code -> spurious
structural-finding(a)); the L-005 rc now propagates end-to-end through the
delegation wrappers (split-declared captures dodge the local x=$() rc mask) to
_rework_pre_pass, which routes a parse failure away from structural-finding(a).

Build LAST: after 0049 impl (PR #142, lands touched-files.sh) AND after the
0050-0054 stack (shares gates.sh/tdd-lint.sh). Nothing stacks on 0055.

Design gate:
  tl_lint rc=0; --bounds rc=0; body 265/500; 8 files, no exception.
  Independent design critique (design-reviewer, sonnet): first pass
  DESIGN_REVIEW: BLOCK on two real gaps — (1) md_bullet_path couldn't serve the
  count/exception Expected-diff callers; (2) the L-005 rc would be masked by
  local x=$() before reaching the membership check. Both fixed (shared
  md_bullet_path_of_line; explicit split-declared rc propagation) + minors
  (count fence walk migrated; A4 sequencing; advisory _coverage_inscope_reqs
  carve-out). Re-review: DESIGN_REVIEW: PASS.
  ADR evaluation: zero new ADRs; ADR 0006 governs and is respected.

Open assumptions & waivers:
- authoring against unmerged 0049 interface — resolved: 0049 DESIGN (#140) locks the tl_extract_touched_paths interface; 0055 declares the 0049-impl build-dependency and builds after #142.
- md_section_body must preserve each caller in-section predicate — resolved: md_section_body emits raw fence-aware in-section lines; each caller keeps its own predicate.
- honoring ~~~ fences changes behavior — resolved: md_section_body treats ``` AND ~~~ as fences; the ```-only parsers mis-handle ~~~ (the bug); honoring it is the fix, regression-pinned.
- L-005 awk-rc check semantics — resolved: md_bullet_path checks awk rc; non-zero → rc 2 + stderr (never silent empty), so parse-fail is distinguishable from a genuinely-empty section.
- touched-files delegate must not change output or break 0049 cross-check — resolved: tl_extract_touched_paths keeps name/signature/output; the 0049 3-way agreement test still passes (Verification pins it).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Same treatment as the 0050-0054 drafts (PR #145): the build-applied version bump
is now in 0055's declared scope. The 9th touched file pushes the count to 9 > the
default THROUGHLINE_TDD_MAX_TOUCHED=8, so 0055 builds with that knob set to 9.
(Caveat unchanged: build-prompt.md still has no bump instruction, so this only
keeps an undeclared bump in-scope; a reliable bump needs the deferred build-prompt fix.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cahenesy cahenesy merged commit 66556ee into master Jun 11, 2026
1 check passed
@cahenesy cahenesy deleted the docs/design/markdown-parser-unification-0055 branch June 11, 2026 13:48
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.

1 participant