Skip to content

feat(scanner): source-markdown scanner + fixer (#1963) - #1965

Merged
jung-thomas merged 2 commits into
DEVfrom
worktree-md-source-scanner-1963
Aug 21, 2026
Merged

feat(scanner): source-markdown scanner + fixer (#1963)#1965
jung-thomas merged 2 commits into
DEVfrom
worktree-md-source-scanner-1963

Conversation

@jung-thomas

Copy link
Copy Markdown
Contributor

Closes #1963 (subsystem B — source-markdown scanner/fixer; attachment dead-links are subsystem A, tracked separately).

What

A CLI (npm run scan-tutorial-markdown) that detects the malformed-markdown classes our render pipeline currently patches in flight (scripts/parsers/*.ts), fixes them at source, and opens one PR per sap-tutorials source repo — so the pre-processors can eventually be retired.

Key insight: each pre-processor is a pure, idempotent (md)=>md transform, so each is its own fixer (finding = output ≠ input). Applying the fix at source + re-running the still-present pre-processor yields byte-identical compose output — the golden-render gate.

Classes

Source-fixable (detected + fixed): blockquote-fence, list-continuation-fence (#1931), list-continuation-prose, blockquote-notes (#1741), image-directive-comment (#1137).
Render-time (report-only, never written): hugo-delimiters. (Image URL rewrite / prerequisites-markup are correct at source and excluded.)

Design

  • Reuses the exact pre-processor transforms → scanner and pipeline can never disagree. stripImageDirectiveComments extracted from images.ts for the same reason.
  • Frontmatter kept byte-for-byte; only the body is transformed. Original EOL (CRLF/LF) preserved.
  • LCS line-diff for accurate source-space line numbers.
  • Golden-render gate asserts {steps, body, intro} equality (the pre-processor-governed fields) before any file is written/PR'd; failures are quarantined as NEEDS-MANUAL-REVIEW.
  • Flags: dry-run (default) → --fix (stage) → --open-prs (clone + re-gate against fresh source + PR per repo). --retirement-status, --class/--repo/--slug/--limit.

Scale (current cache)

17,614 findings across 855 files. Source-fixable spans 15 repos / 847 files; golden gate passes all 847 (0 manual-review). list-continuation-fence = 450 files (matches the issue's ~469 estimate).

Retirement

--retirement-status reports per-class remaining occurrences and, at zero, the exact removal checklist. Deletion is deferred — gated on merged source PRs (none are zero yet).

Tests

test/parsers/scan-markdown-source.test.ts (14): per-class detection, idempotency (fix→re-scan=0), golden-render, frontmatter + EOL preservation, render-time never written. Existing images.test.ts + compose.test.ts still green.

Verification done

First live source PR opened + inspected: sap-tutorials/eda#7 (clean, conservative de-indent). Remaining repos pending maintainer go-ahead given the footprint.

🤖 Generated with Claude Code

Detect + fix at source the malformed-markdown classes the render pipeline
currently patches in flight (scripts/parsers/*.ts pre-processors), and open one
PR per sap-tutorials source repo so the pre-processors can be retired.

- scripts/scan-markdown-source.ts: registry of 5 source-fixable classes
  (blockquote-fence, list-continuation-fence #1931, list-continuation-prose,
  blockquote-notes #1741, image-directive-comment #1137) reusing the exact
  pre-processor transforms, plus render-time hugo-delimiters (report-only).
  Frontmatter-verbatim split, EOL preservation, LCS line-diff findings,
  golden-render gate (steps/body/intro equality), dry-run default, --fix,
  --open-prs (clone+re-gate+PR per repo), --retirement-status.
- scripts/parsers/images.ts: extract stripImageDirectiveComments so scanner and
  pre-processor share one #1137 transform (behavior-preserving).
- test/parsers/scan-markdown-source.test.ts: detection, idempotency,
  golden-render, frontmatter + EOL preservation, render-time never written.

Retirement of the in-flight pre-processors is gated on merged source PRs and is
NOT performed here.

🤖 Generated with Claude Code
- --open-prs now also targets each published repo's <repo>-Contribution
  upstream (default on; --no-contribution to disable), so a source fix can't be
  overwritten the next time Contribution is copied forward. PR flow is now
  clone-driven: each repo is cloned and re-scanned against its own current
  content, golden-gated, then fixed — works for Contribution repos not in the
  local discovery cache.
- Fixes are chunked into ≤--batch-size (default 10) tutorials per PR, one branch
  (fix/md-source-1963[-batch-N]) + PR each, so large repos stay reviewable.
- Idempotent: skips a batch whose head branch already has a PR (any state).
- chunk() extracted + unit-tested.

🤖 Generated with Claude Code
@jung-thomas

Copy link
Copy Markdown
Contributor Author

Updated per review feedback:

  • Contribution sync: --open-prs now also targets each published repo's <repo>-Contribution upstream (default on; --no-contribution to disable). The PR flow is clone-driven — each repo is cloned and re-scanned against its own current content — so a source fix can't be silently reverted the next time Contribution is copied forward. Confirmed: every affected repo has a -Contribution pair carrying the same defects.
  • Batched PRs: fixes are split into ≤--batch-size (default 10) tutorials per PR (branch fix/md-source-1963[-batch-N]), so large repos (Tutorials = 375 files) stay reviewable. Idempotent: a batch whose head branch already has a PR is skipped.

Live verification: sap-tutorials/eda-Contribution#1 (the Contribution pair for the earlier eda#7).

@jung-thomas
jung-thomas merged commit 87de8b4 into DEV Aug 21, 2026
5 checks passed
@jung-thomas
jung-thomas deleted the worktree-md-source-scanner-1963 branch August 21, 2026 19:06
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