check-new-line-breaks.yml

Advisory, diff-scoped check that flags newly-added Markdown lines packing more than one sentence/clause onto a single source line – the “semantic line breaks” convention (one clause/sentence per line), which keeps a diff scoped to the changed sentence instead of a whole reflowed paragraph. Scoped to lines a diff adds, so it never reflags a corpus’s pre-existing long lines. Pairs well with lint-markdown.yml when markdownlint’s MD013 (line-length) is disabled because the corpus already carries long-line drift from before the convention was adopted.

Two checks run, both on by default. The first is the SemBr spec’s rule 4, the normative MUST: break after a sentence. The second flags a long line carrying a mid-line semicolon, as a proxy for its rule 5, the SHOULD: break after an independent clause. It is a proxy rather than a test of the rule, since deciding whether a mark ends an independent clause needs a parser – so a semicolon-delimited list can be flagged too. Of the four marks rule 5 names, only the semicolon has a low enough unparsed hit rate to be useful: keying on all four flags 50.5% of already-conforming prose, against 0.7% for this check; see gha#336 for the measurements.

The gate’s default of 80 is the spec’s own rule 12, “a maximum line length of 80 characters is RECOMMENDED”. It measures a line’s visible length – rule 13 exempts a line that is long to accommodate a hyperlink or a code element – so a line that is long only because of a link target or a code span does not qualify. Set clause-breaks: false to check sentences only.

Inputs

Input Type Default Description
python-version string '3.x' Python version to set up.
globs string '*.md' Space-separated git pathspecs of tracked files to check (recursive by default).
paths-ignore string '' Comma- or newline-separated glob patterns (relative paths) to skip; supports *, ?, and recursive **.
fail boolean false Fail the workflow when a violation is found; otherwise warn only.
clause-breaks boolean true Also flag a long line carrying a mid-line semicolon (a proxy for SemBr rule 5), on top of the rule 4 sentence check that always runs. Set false to check sentences only.
clause-min-length string '80' Minimum line length before clause-breaks applies, inclusive. Measured on visible prose, after stripping inline markup such as code spans, link targets, bare URLs, and HTML entities, so a line long only because of a URL does not qualify. Ignored when clause-breaks is false.

Permissions

Only contents: read (the default), so no permissions: block is needed.

Example

# Copy to .github/workflows/check-new-line-breaks.yml in your repo.
# Advisory check: flags newly-added Markdown lines packing more than one
# sentence/clause onto one source line. Diff-scoped, so it only ever flags
# what a PR itself adds -- pairs well with lint-markdown when MD013
# (line-length) is disabled because the corpus already has long-line drift.
# Only contents:read is needed (the default), so no permissions block is required.
name: Check new markdown lines for missing semantic breaks

on:
  push:
    branches:
      - main
  pull_request:
  workflow_dispatch:

jobs:
  check:
    uses: Morrison-Lab/gha/.github/workflows/check-new-line-breaks.yml@v2
    # with:
    #   globs: '*.md'                          # pathspecs to check (recursive)
    #   paths-ignore: 'CHANGELOG.md,vendor/*'  # skip known-noisy paths
    #   fail: true                             # block the PR instead of warning
    #   clause-breaks: false                   # sentences only; skip the
    #                                          # semicolon clause check (on by default)
    #   clause-min-length: 100                 # raise the clause check's length gate

See examples/check-new-line-breaks.yml for the full caller stub.