From 060fd319153bd68da398a38e0c9dd929431977ae Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Thu, 9 Jul 2026 22:57:52 +0800 Subject: [PATCH 01/37] Harper --- .github/workflows/docs-quality.yml | 64 ++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/workflows/docs-quality.yml diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml new file mode 100644 index 0000000000..e14581ab06 --- /dev/null +++ b/.github/workflows/docs-quality.yml @@ -0,0 +1,64 @@ +name: Docs Quality + +on: + pull_request: + paths: + - "docs/**/*.md" + - "_typos.toml" + - ".github/workflows/docs-quality.yml" + push: + branches: [main] + workflow_dispatch: {} # lets you run it manually from the Actions tab + +permissions: + contents: read + +jobs: + # ── Spelling ──────────────────────────────────────────────── + # typos-cli reads _typos.toml at the repo root automatically. + # This is the ONLY spelling dictionary we maintain. + typos: + name: Spelling (typos-cli) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run typos + uses: crate-ci/typos@master # consider pinning to a tag, e.g. @v1.29.0 + + # ── Grammar / style + heading title-case ──────────────────── + # Harper with SpellCheck disabled (typos-cli owns spelling). + # UseTitleCase is on by default in harper-cli. + harper: + name: Grammar & headings (Harper) + runs-on: ubuntu-latest + # Report-only for now: the first run will flag every historical + # non-title-case heading, and we don't want that blocking PRs yet. + # Once the docs are cleaned up, remove this line to make it a gate. + continue-on-error: true + steps: + - uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + + - name: Cache cargo build + uses: Swatinem/rust-cache@v2 + + - name: Install harper-cli + # Experimental CLI, source-installed. First build is slow (~5-10 min); + # the cache above makes subsequent runs fast. + run: cargo install --locked --git https://github.com/Automattic/harper.git harper-cli + + - name: Lint docs with Harper (spellcheck off) + run: | + set -uo pipefail + status=0 + # harper-cli lint takes one file at a time, so loop over docs/**/*.md + while IFS= read -r -d '' file; do + echo "::group::$file" + if ! harper-cli lint --ignore SpellCheck "$file"; then + status=1 + fi + echo "::endgroup::" + done < <(find docs -name '*.md' -print0) + exit $status From d9930bdb569c1b0354de581e43eaa4f950002334 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Thu, 9 Jul 2026 23:03:04 +0800 Subject: [PATCH 02/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index e14581ab06..2d6409cfab 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -8,52 +8,41 @@ on: - ".github/workflows/docs-quality.yml" push: branches: [main] - workflow_dispatch: {} # lets you run it manually from the Actions tab + workflow_dispatch: {} permissions: contents: read jobs: - # ── Spelling ──────────────────────────────────────────────── - # typos-cli reads _typos.toml at the repo root automatically. - # This is the ONLY spelling dictionary we maintain. typos: name: Spelling (typos-cli) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Run typos - uses: crate-ci/typos@master # consider pinning to a tag, e.g. @v1.29.0 + - uses: crate-ci/typos@master - # ── Grammar / style + heading title-case ──────────────────── - # Harper with SpellCheck disabled (typos-cli owns spelling). - # UseTitleCase is on by default in harper-cli. harper: name: Grammar & headings (Harper) runs-on: ubuntu-latest - # Report-only for now: the first run will flag every historical - # non-title-case heading, and we don't want that blocking PRs yet. - # Once the docs are cleaned up, remove this line to make it a gate. continue-on-error: true steps: - uses: actions/checkout@v4 - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - - - name: Cache cargo build - uses: Swatinem/rust-cache@v2 + - name: Cache harper-cli binary + id: cache-harper + uses: actions/cache@v4 + with: + path: ~/.cargo/bin/harper-cli + key: harper-cli-${{ runner.os }}-v1 - name: Install harper-cli - # Experimental CLI, source-installed. First build is slow (~5-10 min); - # the cache above makes subsequent runs fast. + if: steps.cache-harper.outputs.cache-hit != 'true' run: cargo install --locked --git https://github.com/Automattic/harper.git harper-cli - name: Lint docs with Harper (spellcheck off) run: | set -uo pipefail status=0 - # harper-cli lint takes one file at a time, so loop over docs/**/*.md while IFS= read -r -d '' file; do echo "::group::$file" if ! harper-cli lint --ignore SpellCheck "$file"; then From 23bc4479333c73cdf72814d4ef1bae82e92db21c Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Thu, 9 Jul 2026 23:22:30 +0800 Subject: [PATCH 03/37] Update _typos.toml with new configurations Added file exclusion patterns and extended identifiers. --- _typos.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/_typos.toml b/_typos.toml index 2b96bd37df..0055076d4b 100644 --- a/_typos.toml +++ b/_typos.toml @@ -1,3 +1,6 @@ +[files] +extend-exclude = ["*", "!*/", "!*.md", "!*.mdx"] + [default.extend-words] # Scientific Software namd = "namd" From 342bbfcdacec3d163fa847640b86ccf1094b7638 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Thu, 9 Jul 2026 23:22:56 +0800 Subject: [PATCH 04/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 2d6409cfab..abfe00427f 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -4,6 +4,7 @@ on: pull_request: paths: - "docs/**/*.md" + - "docs/**/*.mdx" - "_typos.toml" - ".github/workflows/docs-quality.yml" push: @@ -42,12 +43,25 @@ jobs: - name: Lint docs with Harper (spellcheck off) run: | set -uo pipefail - status=0 + out="$(mktemp)" + total=0 + bad=0 while IFS= read -r -d '' file; do + total=$((total+1)) echo "::group::$file" - if ! harper-cli lint --ignore SpellCheck "$file"; then - status=1 + if harper-cli lint --ignore SpellCheck "$file" 2>&1 | tee -a "$out"; then + : + else + bad=$((bad+1)) fi echo "::endgroup::" - done < <(find docs -name '*.md' -print0) - exit $status + done < <(find docs \( -name '*.md' -o -name '*.mdx' \) -print0) + titlecase=$(grep -c 'UseTitleCase' "$out" || true) + { + echo "### Harper summary" + echo "- Files scanned: $total" + echo "- Files with issues: $bad" + echo "- Heading (UseTitleCase) violations: $titlecase" + } >> "$GITHUB_STEP_SUMMARY" + echo "== Harper: $bad/$total files with issues; $titlecase heading (UseTitleCase) violations ==" + [ "$bad" -eq 0 ] From d0f15729a24be7f4c65e0d96aa6801981910461f Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Thu, 9 Jul 2026 23:42:21 +0800 Subject: [PATCH 05/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 34 ++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index abfe00427f..d0b6cb6995 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -40,28 +40,54 @@ jobs: if: steps.cache-harper.outputs.cache-hit != 'true' run: cargo install --locked --git https://github.com/Automattic/harper.git harper-cli - - name: Lint docs with Harper (spellcheck off) + - name: Lint docs with Harper run: | set -uo pipefail + + IGNORED_RULES=( + SpellCheck + OrthographicConsistency + ProperNouns + CompaniesProductsAndTrademarks + GoogleNames AppleNames MicrosoftNames AzureNames AmazonNames MetaNames + JetpackNames TumblrNames PocketCastsNames DayOneNames GoggleBrand WordPressDotcom + LongSentences Hedging FillerWords + ExpandForward ExpandParameter ExpandMinimum ExpandVulnerability + ExpandConfiguration ExpandDereference ExpandArgument ExpandDependencies + ExpandPrevious ExpandThough ExpandDecl ExpandCoordinate ExpandPointer + ExpandStandardInputAndOutput ExpandThrough ExpandTimeShorthands + ExpandMemoryShorthands ExpandControl ExpandAlgorithm ExpandPeople + ExpandNotification ExpandGovt ExpandWith ExpandWithout ExpandBecause + ExpandPreference ExpandPerformance ExpandDirectory ExpandAlloc + ) + IGNORE_ARGS=() + for r in "${IGNORED_RULES[@]}"; do IGNORE_ARGS+=(--ignore "$r"); done + out="$(mktemp)" total=0 bad=0 while IFS= read -r -d '' file; do total=$((total+1)) echo "::group::$file" - if harper-cli lint --ignore SpellCheck "$file" 2>&1 | tee -a "$out"; then + if harper-cli lint "${IGNORE_ARGS[@]}" "$file" 2>&1 | tee -a "$out"; then : else bad=$((bad+1)) fi echo "::endgroup::" done < <(find docs \( -name '*.md' -o -name '*.mdx' \) -print0) - titlecase=$(grep -c 'UseTitleCase' "$out" || true) + + titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) { echo "### Harper summary" echo "- Files scanned: $total" echo "- Files with issues: $bad" echo "- Heading (UseTitleCase) violations: $titlecase" + echo "" + echo "### Violations by rule" + echo '```' + grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn + echo '```' } >> "$GITHUB_STEP_SUMMARY" - echo "== Harper: $bad/$total files with issues; $titlecase heading (UseTitleCase) violations ==" + echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" [ "$bad" -eq 0 ] From 78a1d7272c2a5933b3b100c94454644b82ff08f6 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Thu, 9 Jul 2026 23:55:28 +0800 Subject: [PATCH 06/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index d0b6cb6995..214f6705a9 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -45,6 +45,8 @@ jobs: set -uo pipefail IGNORED_RULES=( + Formatting + Capitalization SpellCheck OrthographicConsistency ProperNouns From 702083d0bccb916b8ff6daa4a35e4ec2b23b0844 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Fri, 10 Jul 2026 00:09:52 +0800 Subject: [PATCH 07/37] Update Docs Quality workflow for Harper checks --- .github/workflows/docs-quality.yml | 82 +++++++++++++++--------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 214f6705a9..1f0ddc2675 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -1,42 +1,29 @@ -name: Docs Quality +name: Harper on: pull_request: - paths: - - "docs/**/*.md" - - "docs/**/*.mdx" - - "_typos.toml" - - ".github/workflows/docs-quality.yml" - push: - branches: [main] - workflow_dispatch: {} - -permissions: - contents: read + workflow_dispatch: jobs: - typos: - name: Spelling (typos-cli) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: crate-ci/typos@master - harper: - name: Grammar & headings (Harper) + name: Grammar and Style Check runs-on: ubuntu-latest - continue-on-error: true + steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v6 - - name: Cache harper-cli binary + - name: Cache Harper CLI id: cache-harper uses: actions/cache@v4 with: - path: ~/.cargo/bin/harper-cli - key: harper-cli-${{ runner.os }}-v1 + path: | + ~/.cargo/bin/harper-cli + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-harper-cli - - name: Install harper-cli + - name: Install Harper CLI if: steps.cache-harper.outputs.cache-hit != 'true' run: cargo install --locked --git https://github.com/Automattic/harper.git harper-cli @@ -45,51 +32,62 @@ jobs: set -uo pipefail IGNORED_RULES=( - Formatting - Capitalization SpellCheck OrthographicConsistency ProperNouns CompaniesProductsAndTrademarks - GoogleNames AppleNames MicrosoftNames AzureNames AmazonNames MetaNames - JetpackNames TumblrNames PocketCastsNames DayOneNames GoggleBrand WordPressDotcom - LongSentences Hedging FillerWords - ExpandForward ExpandParameter ExpandMinimum ExpandVulnerability - ExpandConfiguration ExpandDereference ExpandArgument ExpandDependencies - ExpandPrevious ExpandThough ExpandDecl ExpandCoordinate ExpandPointer - ExpandStandardInputAndOutput ExpandThrough ExpandTimeShorthands - ExpandMemoryShorthands ExpandControl ExpandAlgorithm ExpandPeople - ExpandNotification ExpandGovt ExpandWith ExpandWithout ExpandBecause - ExpandPreference ExpandPerformance ExpandDirectory ExpandAlloc + OkToOkay + DisjointPrefixes + LongSentences + Hedging + FillerWords + EllipsisLength + SentenceCapitalization + Spaces + SplitWords + MassNouns ) + IGNORE_ARGS=() - for r in "${IGNORED_RULES[@]}"; do IGNORE_ARGS+=(--ignore "$r"); done + for rule in "${IGNORED_RULES[@]}"; do + IGNORE_ARGS+=(--ignore "$rule") + done out="$(mktemp)" total=0 bad=0 + while IFS= read -r -d '' file; do total=$((total+1)) echo "::group::$file" + if harper-cli lint "${IGNORE_ARGS[@]}" "$file" 2>&1 | tee -a "$out"; then : else bad=$((bad+1)) fi + echo "::endgroup::" - done < <(find docs \( -name '*.md' -o -name '*.mdx' \) -print0) + done < <( + find docs src/pages \ + -type f \( -name "*.md" -o -name "*.mdx" \) \ + -print0 2>/dev/null + ) titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) + { echo "### Harper summary" echo "- Files scanned: $total" echo "- Files with issues: $bad" - echo "- Heading (UseTitleCase) violations: $titlecase" + echo "- Heading title case violations: $titlecase" echo "" echo "### Violations by rule" echo '```' - grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn + grep -oE '$begin:math:display$\[A\-Za\-z\]\+\:\:\[A\-Za\-z\]\+$end:math:display$' "$out" | sort | uniq -c | sort -rn || true echo '```' } >> "$GITHUB_STEP_SUMMARY" + echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" + [ "$bad" -eq 0 ] From 1c64c78beae646fab1310ebbcede1219f6304097 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Fri, 10 Jul 2026 21:45:57 +0800 Subject: [PATCH 08/37] Enhance docs quality workflow with caching and reporting Added cache reporting and improved linting output. --- .github/workflows/docs-quality.yml | 36 ++++++++++++++++++------------ 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 1f0ddc2675..483c2c412f 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -1,14 +1,11 @@ name: Harper - on: pull_request: workflow_dispatch: - jobs: harper: name: Grammar and Style Check runs-on: ubuntu-latest - steps: - name: Checkout uses: actions/checkout@v6 @@ -22,6 +19,19 @@ jobs: ~/.cargo/registry ~/.cargo/git key: ${{ runner.os }}-harper-cli + restore-keys: | + ${{ runner.os }}-harper-cli + + - name: Report cache status + run: | + echo "cache-hit output: '${{ steps.cache-harper.outputs.cache-hit }}'" + ls -la ~/.cargo/bin/ 2>&1 || echo "~/.cargo/bin does not exist" + if [ -x ~/.cargo/bin/harper-cli ]; then + echo "RESULT: harper-cli binary present and executable" + ~/.cargo/bin/harper-cli --version || true + else + echo "RESULT: harper-cli binary NOT present -- full reinstall will run" + fi - name: Install Harper CLI if: steps.cache-harper.outputs.cache-hit != 'true' @@ -30,7 +40,6 @@ jobs: - name: Lint docs with Harper run: | set -uo pipefail - IGNORED_RULES=( SpellCheck OrthographicConsistency @@ -46,36 +55,37 @@ jobs: Spaces SplitWords MassNouns + ExpandMemoryShorthands + ExpandDirectory + AnA + NoFrenchSpaces + InflectedVerbAfterTo + CapitalizePersonalPronouns + Dashes + ) - IGNORE_ARGS=() for rule in "${IGNORED_RULES[@]}"; do IGNORE_ARGS+=(--ignore "$rule") done - out="$(mktemp)" total=0 bad=0 - while IFS= read -r -d '' file; do total=$((total+1)) echo "::group::$file" - if harper-cli lint "${IGNORE_ARGS[@]}" "$file" 2>&1 | tee -a "$out"; then : else bad=$((bad+1)) fi - echo "::endgroup::" done < <( find docs src/pages \ -type f \( -name "*.md" -o -name "*.mdx" \) \ -print0 2>/dev/null ) - titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) - { echo "### Harper summary" echo "- Files scanned: $total" @@ -84,10 +94,8 @@ jobs: echo "" echo "### Violations by rule" echo '```' - grep -oE '$begin:math:display$\[A\-Za\-z\]\+\:\:\[A\-Za\-z\]\+$end:math:display$' "$out" | sort | uniq -c | sort -rn || true + grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true echo '```' } >> "$GITHUB_STEP_SUMMARY" - echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" - [ "$bad" -eq 0 ] From c931d00d2118736402af52ddc229c297a53171a4 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Fri, 10 Jul 2026 21:54:13 +0800 Subject: [PATCH 09/37] Rename workflow and add typos job --- .github/workflows/docs-quality.yml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 483c2c412f..36e4ac7b71 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -1,15 +1,22 @@ -name: Harper +name: Docs Quality on: pull_request: workflow_dispatch: jobs: + typos: + name: Spelling (typos-cli) + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + - uses: crate-ci/typos@master + harper: name: Grammar and Style Check runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v6 - - name: Cache Harper CLI id: cache-harper uses: actions/cache@v4 @@ -21,7 +28,6 @@ jobs: key: ${{ runner.os }}-harper-cli restore-keys: | ${{ runner.os }}-harper-cli - - name: Report cache status run: | echo "cache-hit output: '${{ steps.cache-harper.outputs.cache-hit }}'" @@ -32,11 +38,9 @@ jobs: else echo "RESULT: harper-cli binary NOT present -- full reinstall will run" fi - - name: Install Harper CLI if: steps.cache-harper.outputs.cache-hit != 'true' run: cargo install --locked --git https://github.com/Automattic/harper.git harper-cli - - name: Lint docs with Harper run: | set -uo pipefail @@ -62,7 +66,6 @@ jobs: InflectedVerbAfterTo CapitalizePersonalPronouns Dashes - ) IGNORE_ARGS=() for rule in "${IGNORED_RULES[@]}"; do From e16822977b9387cde611a28f9a66229e6ff4d21c Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Fri, 10 Jul 2026 22:00:49 +0800 Subject: [PATCH 10/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 58 ++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 36e4ac7b71..eb568b02b8 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -44,22 +44,50 @@ jobs: - name: Lint docs with Harper run: | set -uo pipefail - IGNORED_RULES=( - SpellCheck - OrthographicConsistency - ProperNouns - CompaniesProductsAndTrademarks - OkToOkay - DisjointPrefixes - LongSentences - Hedging - FillerWords - EllipsisLength - SentenceCapitalization - Spaces + ONLY_RULES=( + UseTitleCase + RepeatedWords + UnclosedQuotes + MergeWords SplitWords - MassNouns - ExpandMemoryShorthands + ItsContraction + ThenThan + TheirToThere + TheyreToTheir + ThereToTheir + ) + ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" + out="$(mktemp)" + total=0 + bad=0 + while IFS= read -r -d '' file; do + total=$((total+1)) + echo "::group::$file" + if harper-cli lint $ONLY_ARG "$file" 2>&1 | tee -a "$out"; then + : + else + bad=$((bad+1)) + fi + echo "::endgroup::" + done < <( + find docs src/pages \ + -type f \( -name "*.md" -o -name "*.mdx" \) \ + -print0 2>/dev/null + ) + titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) + { + echo "### Harper summary" + echo "- Files scanned: $total" + echo "- Files with issues: $bad" + echo "- Heading title case violations: $titlecase" + echo "" + echo "### Violations by rule" + echo '```' + grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" + [ "$bad" -eq 0 ] ExpandMemoryShorthands ExpandDirectory AnA NoFrenchSpaces From 1eb3089332efaf99f9979c5383c7a6d9f97387b4 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Fri, 10 Jul 2026 22:08:27 +0800 Subject: [PATCH 11/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index eb568b02b8..1f22c983f3 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -47,14 +47,8 @@ jobs: ONLY_RULES=( UseTitleCase RepeatedWords - UnclosedQuotes MergeWords - SplitWords ItsContraction - ThenThan - TheirToThere - TheyreToTheir - ThereToTheir ) ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" out="$(mktemp)" From f57d4be4f9c18893e026e4c3d200a278eefdfe8e Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Fri, 10 Jul 2026 22:55:19 +0800 Subject: [PATCH 12/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 120 +++++++++++------------------ 1 file changed, 47 insertions(+), 73 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 1f22c983f3..3a75668f65 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -1,98 +1,75 @@ name: Docs Quality + on: pull_request: - workflow_dispatch: + paths: + - "docs/**/*.md" + - "docs/**/*.mdx" + - "_typos.toml" + - ".github/workflows/docs-quality.yml" + push: + branches: [main] + workflow_dispatch: {} + +permissions: + contents: read + jobs: typos: name: Spelling (typos-cli) runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: crate-ci/typos@master harper: - name: Grammar and Style Check + name: Grammar & headings (Harper) runs-on: ubuntu-latest + continue-on-error: true steps: - - name: Checkout - uses: actions/checkout@v6 - - name: Cache Harper CLI + - uses: actions/checkout@v4 + + - name: Cache harper-cli binary id: cache-harper uses: actions/cache@v4 with: - path: | - ~/.cargo/bin/harper-cli - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-harper-cli + path: ~/.cargo/bin/harper-cli + key: harper-cli-${{ runner.os }}-v1 restore-keys: | - ${{ runner.os }}-harper-cli + harper-cli-${{ runner.os }}- + - name: Report cache status run: | echo "cache-hit output: '${{ steps.cache-harper.outputs.cache-hit }}'" - ls -la ~/.cargo/bin/ 2>&1 || echo "~/.cargo/bin does not exist" - if [ -x ~/.cargo/bin/harper-cli ]; then - echo "RESULT: harper-cli binary present and executable" - ~/.cargo/bin/harper-cli --version || true + if [ -f ~/.cargo/bin/harper-cli ]; then + echo "harper-cli binary present at ~/.cargo/bin/harper-cli" else - echo "RESULT: harper-cli binary NOT present -- full reinstall will run" + echo "harper-cli binary NOT present -- will build from source" fi - - name: Install Harper CLI + + - name: Install harper-cli if: steps.cache-harper.outputs.cache-hit != 'true' run: cargo install --locked --git https://github.com/Automattic/harper.git harper-cli + - name: Lint docs with Harper run: | set -uo pipefail - ONLY_RULES=( - UseTitleCase - RepeatedWords - MergeWords - ItsContraction - ) - ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" - out="$(mktemp)" - total=0 - bad=0 - while IFS= read -r -d '' file; do - total=$((total+1)) - echo "::group::$file" - if harper-cli lint $ONLY_ARG "$file" 2>&1 | tee -a "$out"; then - : - else - bad=$((bad+1)) - fi - echo "::endgroup::" - done < <( - find docs src/pages \ - -type f \( -name "*.md" -o -name "*.mdx" \) \ - -print0 2>/dev/null - ) - titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) - { - echo "### Harper summary" - echo "- Files scanned: $total" - echo "- Files with issues: $bad" - echo "- Heading title case violations: $titlecase" - echo "" - echo "### Violations by rule" - echo '```' - grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true - echo '```' - } >> "$GITHUB_STEP_SUMMARY" - echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" - [ "$bad" -eq 0 ] ExpandMemoryShorthands - ExpandDirectory - AnA - NoFrenchSpaces - InflectedVerbAfterTo - CapitalizePersonalPronouns - Dashes + + IGNORED_RULES=( + SpellCheck + OrthographicConsistency + ProperNouns + CompaniesProductsAndTrademarks + GoogleNames MicrosoftNames AmazonNames AzureNames MetaNames + LongSentences Hedging FillerWords + ExpandStandardInputAndOutput ExpandTimeShorthands ExpandMemoryShorthands + ExpandDirectory ExpandArgument ExpandParameter ExpandPointer + ExpandDependencies ExpandControl ExpandAlgorithm ExpandAlloc + ExpandDecl ExpandVulnerability ) IGNORE_ARGS=() - for rule in "${IGNORED_RULES[@]}"; do - IGNORE_ARGS+=(--ignore "$rule") - done + for r in "${IGNORED_RULES[@]}"; do IGNORE_ARGS+=(--ignore "$r"); done + out="$(mktemp)" total=0 bad=0 @@ -105,21 +82,18 @@ jobs: bad=$((bad+1)) fi echo "::endgroup::" - done < <( - find docs src/pages \ - -type f \( -name "*.md" -o -name "*.mdx" \) \ - -print0 2>/dev/null - ) + done < <(find docs \( -name '*.md' -o -name '*.mdx' \) -print0) + titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) { echo "### Harper summary" echo "- Files scanned: $total" echo "- Files with issues: $bad" - echo "- Heading title case violations: $titlecase" + echo "- Heading (UseTitleCase) violations: $titlecase" echo "" echo "### Violations by rule" echo '```' - grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true + grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn echo '```' } >> "$GITHUB_STEP_SUMMARY" echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" From 9c9f731f70bf6e39423c559d97551f5101c6354c Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Fri, 10 Jul 2026 23:06:16 +0800 Subject: [PATCH 13/37] Update docs quality workflow for improvements --- .github/workflows/docs-quality.yml | 104 ++++++++++++++--------------- 1 file changed, 49 insertions(+), 55 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 3a75668f65..9f928f6ca4 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -1,100 +1,94 @@ name: Docs Quality - on: pull_request: - paths: - - "docs/**/*.md" - - "docs/**/*.mdx" - - "_typos.toml" - - ".github/workflows/docs-quality.yml" - push: - branches: [main] - workflow_dispatch: {} - -permissions: - contents: read - + workflow_dispatch: jobs: typos: name: Spelling (typos-cli) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v6 - uses: crate-ci/typos@master harper: - name: Grammar & headings (Harper) + name: Grammar and Style Check runs-on: ubuntu-latest - continue-on-error: true steps: - - uses: actions/checkout@v4 - - - name: Cache harper-cli binary + - name: Checkout + uses: actions/checkout@v6 + - name: Restore Harper CLI cache id: cache-harper - uses: actions/cache@v4 + uses: actions/cache/restore@v4 with: - path: ~/.cargo/bin/harper-cli - key: harper-cli-${{ runner.os }}-v1 + path: | + ~/.cargo/bin/harper-cli + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-harper-cli restore-keys: | - harper-cli-${{ runner.os }}- - + ${{ runner.os }}-harper-cli - name: Report cache status run: | echo "cache-hit output: '${{ steps.cache-harper.outputs.cache-hit }}'" - if [ -f ~/.cargo/bin/harper-cli ]; then - echo "harper-cli binary present at ~/.cargo/bin/harper-cli" + ls -la ~/.cargo/bin/ 2>&1 || echo "~/.cargo/bin does not exist" + if [ -x ~/.cargo/bin/harper-cli ]; then + echo "RESULT: harper-cli binary present and executable" + ~/.cargo/bin/harper-cli --version || true else - echo "harper-cli binary NOT present -- will build from source" + echo "RESULT: harper-cli binary NOT present -- full reinstall will run" fi - - - name: Install harper-cli + - name: Install Harper CLI if: steps.cache-harper.outputs.cache-hit != 'true' run: cargo install --locked --git https://github.com/Automattic/harper.git harper-cli - - name: Lint docs with Harper run: | set -uo pipefail - - IGNORED_RULES=( - SpellCheck - OrthographicConsistency - ProperNouns - CompaniesProductsAndTrademarks - GoogleNames MicrosoftNames AmazonNames AzureNames MetaNames - LongSentences Hedging FillerWords - ExpandStandardInputAndOutput ExpandTimeShorthands ExpandMemoryShorthands - ExpandDirectory ExpandArgument ExpandParameter ExpandPointer - ExpandDependencies ExpandControl ExpandAlgorithm ExpandAlloc - ExpandDecl ExpandVulnerability + ONLY_RULES=( + UseTitleCase + RepeatedWords ) - IGNORE_ARGS=() - for r in "${IGNORED_RULES[@]}"; do IGNORE_ARGS+=(--ignore "$r"); done - - out="$(mktemp)" + ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" + rules_seen="$(mktemp)" total=0 bad=0 while IFS= read -r -d '' file; do total=$((total+1)) echo "::group::$file" - if harper-cli lint "${IGNORE_ARGS[@]}" "$file" 2>&1 | tee -a "$out"; then - : - else + json_out="$(harper-cli lint $ONLY_ARG --format json "$file" 2>/dev/null)" + lint_count=$(printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);print(sum(len(f.get('lints',[])) for f in d))" 2>/dev/null) + if [ "${lint_count:-0}" -gt 0 ]; then bad=$((bad+1)) + printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);[print(l.get('rule','?'), file=sys.stderr) or print('['+l.get('rule','?')+'] '+l.get('message','')+((' -> should be: '+str(l.get('suggestions')[0])) if l.get('suggestions') else '')) for f in d for l in f.get('lints',[])]" 2>>"$rules_seen" + else + echo "no issues" fi echo "::endgroup::" - done < <(find docs \( -name '*.md' -o -name '*.mdx' \) -print0) - - titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) + done < <( + find docs src/pages \ + -type f \( -name "*.md" -o -name "*.mdx" \) \ + -print0 2>/dev/null + ) { echo "### Harper summary" echo "- Files scanned: $total" echo "- Files with issues: $bad" - echo "- Heading (UseTitleCase) violations: $titlecase" echo "" echo "### Violations by rule" echo '```' - grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn + sort "$rules_seen" | uniq -c | sort -rn || true echo '```' } >> "$GITHUB_STEP_SUMMARY" - echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" + + echo "== Harper: $bad/$total files with issues ==" [ "$bad" -eq 0 ] + + - name: Save Harper CLI cache + if: always() && steps.cache-harper.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: | + ~/.cargo/bin/harper-cli + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-harper-cli From 0eb37ab0c13dfe89b70599d97f2764f987b491c1 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Fri, 10 Jul 2026 23:20:51 +0800 Subject: [PATCH 14/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 9f928f6ca4..0fd0cc494b 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -14,6 +14,7 @@ jobs: harper: name: Grammar and Style Check runs-on: ubuntu-latest + continue-on-error: true steps: - name: Checkout uses: actions/checkout@v6 From 550a66624ef72221f96866d33be06cc4e680ad08 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Fri, 10 Jul 2026 23:35:23 +0800 Subject: [PATCH 15/37] Refactor linting logic in docs-quality workflow --- .github/workflows/docs-quality.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 0fd0cc494b..a31f559bab 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -56,13 +56,11 @@ jobs: while IFS= read -r -d '' file; do total=$((total+1)) echo "::group::$file" - json_out="$(harper-cli lint $ONLY_ARG --format json "$file" 2>/dev/null)" - lint_count=$(printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);print(sum(len(f.get('lints',[])) for f in d))" 2>/dev/null) - if [ "${lint_count:-0}" -gt 0 ]; then - bad=$((bad+1)) - printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);[print(l.get('rule','?'), file=sys.stderr) or print('['+l.get('rule','?')+'] '+l.get('message','')+((' -> should be: '+str(l.get('suggestions')[0])) if l.get('suggestions') else '')) for f in d for l in f.get('lints',[])]" 2>>"$rules_seen" - else + if json_out="$(harper-cli lint $ONLY_ARG --format json "$file" 2>/dev/null)"; then echo "no issues" + else + bad=$((bad+1)) + printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);[print(l.get('rule','?'), file=sys.stderr) or print('['+l.get('rule','?')+'] '+l.get('message','')+((' -> should be: '+str(l.get('suggestions')[0])) if l.get('suggestions') else '')) for f in d for l in f.get('lints',[])]" 2>>"$rules_seen" || true fi echo "::endgroup::" done < <( From 28d8a7ed55d2d8942dcab79a8cc01d44281d4101 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Fri, 10 Jul 2026 23:42:24 +0800 Subject: [PATCH 16/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index a31f559bab..a13d0c0c6e 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -50,17 +50,18 @@ jobs: RepeatedWords ) ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" - rules_seen="$(mktemp)" + out="$(mktemp)" total=0 bad=0 while IFS= read -r -d '' file; do total=$((total+1)) echo "::group::$file" - if json_out="$(harper-cli lint $ONLY_ARG --format json "$file" 2>/dev/null)"; then + if harper_out="$(harper-cli lint $ONLY_ARG "$file" 2>&1)"; then echo "no issues" else bad=$((bad+1)) - printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);[print(l.get('rule','?'), file=sys.stderr) or print('['+l.get('rule','?')+'] '+l.get('message','')+((' -> should be: '+str(l.get('suggestions')[0])) if l.get('suggestions') else '')) for f in d for l in f.get('lints',[])]" 2>>"$rules_seen" || true + echo "$harper_out" + echo "$harper_out" >> "$out" fi echo "::endgroup::" done < <( @@ -75,7 +76,7 @@ jobs: echo "" echo "### Violations by rule" echo '```' - sort "$rules_seen" | uniq -c | sort -rn || true + grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true echo '```' } >> "$GITHUB_STEP_SUMMARY" From afb553eb81c7b7f7ad60de571b5d107265bf923b Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Fri, 10 Jul 2026 23:52:36 +0800 Subject: [PATCH 17/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 93 +++++++++++++++--------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index a13d0c0c6e..7733d6662a 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -1,94 +1,95 @@ name: Docs Quality + on: pull_request: - workflow_dispatch: + paths: + - "docs/**/*.md" + - "docs/**/*.mdx" + - "_typos.toml" + - ".github/workflows/docs-quality.yml" + push: + branches: [main] + workflow_dispatch: {} + +permissions: + contents: read + jobs: typos: name: Spelling (typos-cli) runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: crate-ci/typos@master harper: - name: Grammar and Style Check + name: Grammar & headings (Harper) runs-on: ubuntu-latest continue-on-error: true steps: - - name: Checkout - uses: actions/checkout@v6 - - name: Restore Harper CLI cache + - uses: actions/checkout@v4 + + - name: Cache harper-cli binary id: cache-harper - uses: actions/cache/restore@v4 + uses: actions/cache@v4 with: - path: | - ~/.cargo/bin/harper-cli - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-harper-cli + path: ~/.cargo/bin/harper-cli + key: harper-cli-${{ runner.os }}-v1 restore-keys: | - ${{ runner.os }}-harper-cli + harper-cli-${{ runner.os }}- - name: Report cache status run: | echo "cache-hit output: '${{ steps.cache-harper.outputs.cache-hit }}'" - ls -la ~/.cargo/bin/ 2>&1 || echo "~/.cargo/bin does not exist" - if [ -x ~/.cargo/bin/harper-cli ]; then - echo "RESULT: harper-cli binary present and executable" - ~/.cargo/bin/harper-cli --version || true + if [ -f ~/.cargo/bin/harper-cli ]; then + echo "harper-cli binary present at ~/.cargo/bin/harper-cli" else - echo "RESULT: harper-cli binary NOT present -- full reinstall will run" + echo "harper-cli binary NOT present -- will build from source" fi - - name: Install Harper CLI + - name: Install harper-cli if: steps.cache-harper.outputs.cache-hit != 'true' run: cargo install --locked --git https://github.com/Automattic/harper.git harper-cli + - name: Lint docs with Harper run: | set -uo pipefail - ONLY_RULES=( - UseTitleCase - RepeatedWords + IGNORED_RULES=( + SpellCheck + OrthographicConsistency + ProperNouns + CompaniesProductsAndTrademarks + GoogleNames MicrosoftNames AmazonNames AzureNames MetaNames + LongSentences Hedging FillerWords + ExpandStandardInputAndOutput ExpandTimeShorthands ExpandMemoryShorthands + ExpandDirectory ExpandArgument ExpandParameter ExpandPointer + ExpandDependencies ExpandControl ExpandAlgorithm ExpandAlloc + ExpandDecl ExpandVulnerability ) - ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" + IGNORE_ARGS=() + for r in "${IGNORED_RULES[@]}"; do IGNORE_ARGS+=(--ignore "$r"); done out="$(mktemp)" total=0 bad=0 while IFS= read -r -d '' file; do total=$((total+1)) echo "::group::$file" - if harper_out="$(harper-cli lint $ONLY_ARG "$file" 2>&1)"; then - echo "no issues" + if harper-cli lint "${IGNORE_ARGS[@]}" "$file" 2>&1 | tee -a "$out"; then + : else bad=$((bad+1)) - echo "$harper_out" - echo "$harper_out" >> "$out" fi echo "::endgroup::" - done < <( - find docs src/pages \ - -type f \( -name "*.md" -o -name "*.mdx" \) \ - -print0 2>/dev/null - ) + done < <(find docs \( -name '*.md' -o -name '*.mdx' \) -print0) + titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) { echo "### Harper summary" echo "- Files scanned: $total" echo "- Files with issues: $bad" + echo "- Heading (UseTitleCase) violations: $titlecase" echo "" echo "### Violations by rule" echo '```' - grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true + grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn echo '```' } >> "$GITHUB_STEP_SUMMARY" - - echo "== Harper: $bad/$total files with issues ==" + echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" [ "$bad" -eq 0 ] - - - name: Save Harper CLI cache - if: always() && steps.cache-harper.outputs.cache-hit != 'true' - uses: actions/cache/save@v4 - with: - path: | - ~/.cargo/bin/harper-cli - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-harper-cli From 5a9209f5f925ad09a657d623ddbffe882578ec55 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sat, 11 Jul 2026 00:02:01 +0800 Subject: [PATCH 18/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 115 ++++++++++++++++++----------- 1 file changed, 73 insertions(+), 42 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 7733d6662a..1f22c983f3 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -1,71 +1,98 @@ name: Docs Quality - on: pull_request: - paths: - - "docs/**/*.md" - - "docs/**/*.mdx" - - "_typos.toml" - - ".github/workflows/docs-quality.yml" - push: - branches: [main] - workflow_dispatch: {} - -permissions: - contents: read - + workflow_dispatch: jobs: typos: name: Spelling (typos-cli) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v6 - uses: crate-ci/typos@master harper: - name: Grammar & headings (Harper) + name: Grammar and Style Check runs-on: ubuntu-latest - continue-on-error: true steps: - - uses: actions/checkout@v4 - - - name: Cache harper-cli binary + - name: Checkout + uses: actions/checkout@v6 + - name: Cache Harper CLI id: cache-harper uses: actions/cache@v4 with: - path: ~/.cargo/bin/harper-cli - key: harper-cli-${{ runner.os }}-v1 + path: | + ~/.cargo/bin/harper-cli + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-harper-cli restore-keys: | - harper-cli-${{ runner.os }}- + ${{ runner.os }}-harper-cli - name: Report cache status run: | echo "cache-hit output: '${{ steps.cache-harper.outputs.cache-hit }}'" - if [ -f ~/.cargo/bin/harper-cli ]; then - echo "harper-cli binary present at ~/.cargo/bin/harper-cli" + ls -la ~/.cargo/bin/ 2>&1 || echo "~/.cargo/bin does not exist" + if [ -x ~/.cargo/bin/harper-cli ]; then + echo "RESULT: harper-cli binary present and executable" + ~/.cargo/bin/harper-cli --version || true else - echo "harper-cli binary NOT present -- will build from source" + echo "RESULT: harper-cli binary NOT present -- full reinstall will run" fi - - name: Install harper-cli + - name: Install Harper CLI if: steps.cache-harper.outputs.cache-hit != 'true' run: cargo install --locked --git https://github.com/Automattic/harper.git harper-cli - - name: Lint docs with Harper run: | set -uo pipefail - IGNORED_RULES=( - SpellCheck - OrthographicConsistency - ProperNouns - CompaniesProductsAndTrademarks - GoogleNames MicrosoftNames AmazonNames AzureNames MetaNames - LongSentences Hedging FillerWords - ExpandStandardInputAndOutput ExpandTimeShorthands ExpandMemoryShorthands - ExpandDirectory ExpandArgument ExpandParameter ExpandPointer - ExpandDependencies ExpandControl ExpandAlgorithm ExpandAlloc - ExpandDecl ExpandVulnerability + ONLY_RULES=( + UseTitleCase + RepeatedWords + MergeWords + ItsContraction + ) + ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" + out="$(mktemp)" + total=0 + bad=0 + while IFS= read -r -d '' file; do + total=$((total+1)) + echo "::group::$file" + if harper-cli lint $ONLY_ARG "$file" 2>&1 | tee -a "$out"; then + : + else + bad=$((bad+1)) + fi + echo "::endgroup::" + done < <( + find docs src/pages \ + -type f \( -name "*.md" -o -name "*.mdx" \) \ + -print0 2>/dev/null + ) + titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) + { + echo "### Harper summary" + echo "- Files scanned: $total" + echo "- Files with issues: $bad" + echo "- Heading title case violations: $titlecase" + echo "" + echo "### Violations by rule" + echo '```' + grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" + [ "$bad" -eq 0 ] ExpandMemoryShorthands + ExpandDirectory + AnA + NoFrenchSpaces + InflectedVerbAfterTo + CapitalizePersonalPronouns + Dashes ) IGNORE_ARGS=() - for r in "${IGNORED_RULES[@]}"; do IGNORE_ARGS+=(--ignore "$r"); done + for rule in "${IGNORED_RULES[@]}"; do + IGNORE_ARGS+=(--ignore "$rule") + done out="$(mktemp)" total=0 bad=0 @@ -78,17 +105,21 @@ jobs: bad=$((bad+1)) fi echo "::endgroup::" - done < <(find docs \( -name '*.md' -o -name '*.mdx' \) -print0) + done < <( + find docs src/pages \ + -type f \( -name "*.md" -o -name "*.mdx" \) \ + -print0 2>/dev/null + ) titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) { echo "### Harper summary" echo "- Files scanned: $total" echo "- Files with issues: $bad" - echo "- Heading (UseTitleCase) violations: $titlecase" + echo "- Heading title case violations: $titlecase" echo "" echo "### Violations by rule" echo '```' - grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn + grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true echo '```' } >> "$GITHUB_STEP_SUMMARY" echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" From 573987bf355b65bf7b1c4b05305a4689194170f7 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sat, 11 Jul 2026 20:50:18 +0800 Subject: [PATCH 19/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 1f22c983f3..ab94896b8b 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -124,3 +124,19 @@ jobs: } >> "$GITHUB_STEP_SUMMARY" echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" [ "$bad" -eq 0 ] + + - name: Annotate PR with Harper warnings + if: always() + run: | + set -uo pipefail + while IFS= read -r -d '' file; do + if json_out="$(harper-cli lint $ONLY_ARG --format json "$file" 2>/dev/null)"; then + : + else + printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);esc=lambda s: s.replace('%','%25').replace('\r','%0D').replace('\n','%0A');[print('::warning file='+esc(f.get('file',''))+',line='+str(l.get('line',1))+',col='+str(l.get('column',1))+',title='+esc(l.get('rule','?'))+'::'+esc(l.get('message',''))) for f in d for l in f.get('lints',[])]" || true + fi + done < <( + find docs src/pages \ + -type f \( -name "*.md" -o -name "*.mdx" \) \ + -print0 2>/dev/null + ) From 78961d0f4a080f22f832b57b92511acbd1206ba0 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sat, 11 Jul 2026 20:54:35 +0800 Subject: [PATCH 20/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index ab94896b8b..f8080ee0d9 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -129,6 +129,11 @@ jobs: if: always() run: | set -uo pipefail + ONLY_RULES=( + UseTitleCase + RepeatedWords + ) + ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" while IFS= read -r -d '' file; do if json_out="$(harper-cli lint $ONLY_ARG --format json "$file" 2>/dev/null)"; then : From d5a0881e23f3f4f351dc74379abc65784365e301 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sat, 11 Jul 2026 21:04:18 +0800 Subject: [PATCH 21/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 90 +++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 26 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index f8080ee0d9..bea4de769d 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -1,68 +1,106 @@ name: Docs Quality + on: pull_request: - workflow_dispatch: + paths: + - "docs/**/*.md" + - "docs/**/*.mdx" + - "_typos.toml" + - ".github/workflows/docs-quality.yml" + push: + branches: [main] + workflow_dispatch: {} + +permissions: + contents: read + jobs: typos: name: Spelling (typos-cli) runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: crate-ci/typos@master harper: - name: Grammar and Style Check + name: Grammar & headings (Harper) runs-on: ubuntu-latest + continue-on-error: true steps: - - name: Checkout - uses: actions/checkout@v6 - - name: Cache Harper CLI + - uses: actions/checkout@v4 + + - name: Cache harper-cli binary id: cache-harper uses: actions/cache@v4 with: - path: | - ~/.cargo/bin/harper-cli - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-harper-cli + path: ~/.cargo/bin/harper-cli + key: harper-cli-${{ runner.os }}-v1 restore-keys: | - ${{ runner.os }}-harper-cli + harper-cli-${{ runner.os }}- + - name: Report cache status run: | echo "cache-hit output: '${{ steps.cache-harper.outputs.cache-hit }}'" - ls -la ~/.cargo/bin/ 2>&1 || echo "~/.cargo/bin does not exist" - if [ -x ~/.cargo/bin/harper-cli ]; then - echo "RESULT: harper-cli binary present and executable" - ~/.cargo/bin/harper-cli --version || true + if [ -f ~/.cargo/bin/harper-cli ]; then + echo "harper-cli binary present at ~/.cargo/bin/harper-cli" else - echo "RESULT: harper-cli binary NOT present -- full reinstall will run" + echo "harper-cli binary NOT present -- will build from source" fi - - name: Install Harper CLI + + - name: Install harper-cli if: steps.cache-harper.outputs.cache-hit != 'true' run: cargo install --locked --git https://github.com/Automattic/harper.git harper-cli + - name: Lint docs with Harper run: | set -uo pipefail - ONLY_RULES=( - UseTitleCase - RepeatedWords - MergeWords - ItsContraction + + IGNORED_RULES=( + SpellCheck + OrthographicConsistency + ProperNouns + CompaniesProductsAndTrademarks + GoogleNames MicrosoftNames AmazonNames AzureNames MetaNames + LongSentences Hedging FillerWords + ExpandStandardInputAndOutput ExpandTimeShorthands ExpandMemoryShorthands + ExpandDirectory ExpandArgument ExpandParameter ExpandPointer + ExpandDependencies ExpandControl ExpandAlgorithm ExpandAlloc + ExpandDecl ExpandVulnerability ) - ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" + IGNORE_ARGS=() + for r in "${IGNORED_RULES[@]}"; do IGNORE_ARGS+=(--ignore "$r"); done + out="$(mktemp)" total=0 bad=0 while IFS= read -r -d '' file; do total=$((total+1)) echo "::group::$file" - if harper-cli lint $ONLY_ARG "$file" 2>&1 | tee -a "$out"; then + if harper-cli lint "${IGNORE_ARGS[@]}" "$file" 2>&1 | tee -a "$out"; then : else bad=$((bad+1)) fi echo "::endgroup::" + done < <(find docs \( -name '*.md' -o -name '*.mdx' \) -print0) + + titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) + { + echo "### Harper summary" + echo "- Files scanned: $total" + echo "- Files with issues: $bad" + echo "- Heading (UseTitleCase) violations: $titlecase" + echo "" + echo "### Violations by rule" + echo '```' + grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" + [ "$bad" -eq 0 ] else + bad=$((bad+1)) + fi + echo "::endgroup::" done < <( find docs src/pages \ -type f \( -name "*.md" -o -name "*.mdx" \) \ From 18b9fa49e71dbd8ae06475b8f5a6b5e0fff564fc Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sat, 11 Jul 2026 21:14:24 +0800 Subject: [PATCH 22/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 121 +++++++++++++++++++++-------- 1 file changed, 87 insertions(+), 34 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index bea4de769d..5dfd5c44b0 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -1,65 +1,118 @@ name: Docs Quality - on: pull_request: - paths: - - "docs/**/*.md" - - "docs/**/*.mdx" - - "_typos.toml" - - ".github/workflows/docs-quality.yml" - push: - branches: [main] - workflow_dispatch: {} - -permissions: - contents: read - + workflow_dispatch: jobs: typos: name: Spelling (typos-cli) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v6 - uses: crate-ci/typos@master harper: - name: Grammar & headings (Harper) + name: Grammar and Style Check runs-on: ubuntu-latest continue-on-error: true steps: - - uses: actions/checkout@v4 - - - name: Cache harper-cli binary + - name: Checkout + uses: actions/checkout@v6 + - name: Restore Harper CLI cache id: cache-harper - uses: actions/cache@v4 + uses: actions/cache/restore@v4 with: - path: ~/.cargo/bin/harper-cli - key: harper-cli-${{ runner.os }}-v1 + path: | + ~/.cargo/bin/harper-cli + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-harper-cli restore-keys: | - harper-cli-${{ runner.os }}- - + ${{ runner.os }}-harper-cli - name: Report cache status run: | echo "cache-hit output: '${{ steps.cache-harper.outputs.cache-hit }}'" - if [ -f ~/.cargo/bin/harper-cli ]; then - echo "harper-cli binary present at ~/.cargo/bin/harper-cli" + ls -la ~/.cargo/bin/ 2>&1 || echo "~/.cargo/bin does not exist" + if [ -x ~/.cargo/bin/harper-cli ]; then + echo "RESULT: harper-cli binary present and executable" + ~/.cargo/bin/harper-cli --version || true else - echo "harper-cli binary NOT present -- will build from source" + echo "RESULT: harper-cli binary NOT present -- full reinstall will run" fi - - - name: Install harper-cli + - name: Install Harper CLI if: steps.cache-harper.outputs.cache-hit != 'true' run: cargo install --locked --git https://github.com/Automattic/harper.git harper-cli - - name: Lint docs with Harper run: | set -uo pipefail + ONLY_RULES=( + UseTitleCase + RepeatedWords + ) + ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" + out="$(mktemp)" + total=0 + bad=0 + while IFS= read -r -d '' file; do + total=$((total+1)) + echo "::group::$file" + if harper_out="$(harper-cli lint $ONLY_ARG "$file" 2>&1)"; then + echo "no issues" + else + bad=$((bad+1)) + echo "$harper_out" + echo "$harper_out" >> "$out" + fi + echo "::endgroup::" + done < <( + find docs src/pages \ + -type f \( -name "*.md" -o -name "*.mdx" \) \ + -print0 2>/dev/null + ) + { + echo "### Harper summary" + echo "- Files scanned: $total" + echo "- Files with issues: $bad" + echo "" + echo "### Violations by rule" + echo '```' + grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + + echo "== Harper: $bad/$total files with issues ==" + [ "$bad" -eq 0 ] + + - name: Annotate PR with Harper warnings + if: always() + run: | + set -uo pipefail + ONLY_RULES=( + UseTitleCase + RepeatedWords + ) + ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" + while IFS= read -r -d '' file; do + if json_out="$(harper-cli lint $ONLY_ARG --format json "$file" 2>/dev/null)"; then + : + else + printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);esc=lambda s: s.replace('%','%25').replace('\r','%0D').replace('\n','%0A');[print('::warning file='+esc(f.get('file',''))+',line='+str(l.get('line',1))+',col='+str(l.get('column',1))+',title='+esc(l.get('rule','?'))+'::'+esc(l.get('message',''))) for f in d for l in f.get('lints',[])]" || true + fi + done < <( + find docs src/pages \ + -type f \( -name "*.md" -o -name "*.mdx" \) \ + -print0 2>/dev/null + ) - IGNORED_RULES=( - SpellCheck - OrthographicConsistency - ProperNouns - CompaniesProductsAndTrademarks + - name: Save Harper CLI cache + if: always() && steps.cache-harper.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: | + ~/.cargo/bin/harper-cli + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-harper-cli CompaniesProductsAndTrademarks GoogleNames MicrosoftNames AmazonNames AzureNames MetaNames LongSentences Hedging FillerWords ExpandStandardInputAndOutput ExpandTimeShorthands ExpandMemoryShorthands From 83f2e85291d239688c6795e8f2bddb3936d31103 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sat, 11 Jul 2026 21:24:08 +0800 Subject: [PATCH 23/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 207 +++++------------------------ 1 file changed, 32 insertions(+), 175 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 5dfd5c44b0..7733d6662a 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -1,118 +1,62 @@ name: Docs Quality + on: pull_request: - workflow_dispatch: + paths: + - "docs/**/*.md" + - "docs/**/*.mdx" + - "_typos.toml" + - ".github/workflows/docs-quality.yml" + push: + branches: [main] + workflow_dispatch: {} + +permissions: + contents: read + jobs: typos: name: Spelling (typos-cli) runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: crate-ci/typos@master harper: - name: Grammar and Style Check + name: Grammar & headings (Harper) runs-on: ubuntu-latest continue-on-error: true steps: - - name: Checkout - uses: actions/checkout@v6 - - name: Restore Harper CLI cache + - uses: actions/checkout@v4 + + - name: Cache harper-cli binary id: cache-harper - uses: actions/cache/restore@v4 + uses: actions/cache@v4 with: - path: | - ~/.cargo/bin/harper-cli - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-harper-cli + path: ~/.cargo/bin/harper-cli + key: harper-cli-${{ runner.os }}-v1 restore-keys: | - ${{ runner.os }}-harper-cli + harper-cli-${{ runner.os }}- - name: Report cache status run: | echo "cache-hit output: '${{ steps.cache-harper.outputs.cache-hit }}'" - ls -la ~/.cargo/bin/ 2>&1 || echo "~/.cargo/bin does not exist" - if [ -x ~/.cargo/bin/harper-cli ]; then - echo "RESULT: harper-cli binary present and executable" - ~/.cargo/bin/harper-cli --version || true + if [ -f ~/.cargo/bin/harper-cli ]; then + echo "harper-cli binary present at ~/.cargo/bin/harper-cli" else - echo "RESULT: harper-cli binary NOT present -- full reinstall will run" + echo "harper-cli binary NOT present -- will build from source" fi - - name: Install Harper CLI + - name: Install harper-cli if: steps.cache-harper.outputs.cache-hit != 'true' run: cargo install --locked --git https://github.com/Automattic/harper.git harper-cli - - name: Lint docs with Harper - run: | - set -uo pipefail - ONLY_RULES=( - UseTitleCase - RepeatedWords - ) - ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" - out="$(mktemp)" - total=0 - bad=0 - while IFS= read -r -d '' file; do - total=$((total+1)) - echo "::group::$file" - if harper_out="$(harper-cli lint $ONLY_ARG "$file" 2>&1)"; then - echo "no issues" - else - bad=$((bad+1)) - echo "$harper_out" - echo "$harper_out" >> "$out" - fi - echo "::endgroup::" - done < <( - find docs src/pages \ - -type f \( -name "*.md" -o -name "*.mdx" \) \ - -print0 2>/dev/null - ) - { - echo "### Harper summary" - echo "- Files scanned: $total" - echo "- Files with issues: $bad" - echo "" - echo "### Violations by rule" - echo '```' - grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true - echo '```' - } >> "$GITHUB_STEP_SUMMARY" - echo "== Harper: $bad/$total files with issues ==" - [ "$bad" -eq 0 ] - - - name: Annotate PR with Harper warnings - if: always() + - name: Lint docs with Harper run: | set -uo pipefail - ONLY_RULES=( - UseTitleCase - RepeatedWords - ) - ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" - while IFS= read -r -d '' file; do - if json_out="$(harper-cli lint $ONLY_ARG --format json "$file" 2>/dev/null)"; then - : - else - printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);esc=lambda s: s.replace('%','%25').replace('\r','%0D').replace('\n','%0A');[print('::warning file='+esc(f.get('file',''))+',line='+str(l.get('line',1))+',col='+str(l.get('column',1))+',title='+esc(l.get('rule','?'))+'::'+esc(l.get('message',''))) for f in d for l in f.get('lints',[])]" || true - fi - done < <( - find docs src/pages \ - -type f \( -name "*.md" -o -name "*.mdx" \) \ - -print0 2>/dev/null - ) - - - name: Save Harper CLI cache - if: always() && steps.cache-harper.outputs.cache-hit != 'true' - uses: actions/cache/save@v4 - with: - path: | - ~/.cargo/bin/harper-cli - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-harper-cli CompaniesProductsAndTrademarks + IGNORED_RULES=( + SpellCheck + OrthographicConsistency + ProperNouns + CompaniesProductsAndTrademarks GoogleNames MicrosoftNames AmazonNames AzureNames MetaNames LongSentences Hedging FillerWords ExpandStandardInputAndOutput ExpandTimeShorthands ExpandMemoryShorthands @@ -122,7 +66,6 @@ jobs: ) IGNORE_ARGS=() for r in "${IGNORED_RULES[@]}"; do IGNORE_ARGS+=(--ignore "$r"); done - out="$(mktemp)" total=0 bad=0 @@ -136,7 +79,6 @@ jobs: fi echo "::endgroup::" done < <(find docs \( -name '*.md' -o -name '*.mdx' \) -print0) - titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) { echo "### Harper summary" @@ -150,89 +92,4 @@ jobs: echo '```' } >> "$GITHUB_STEP_SUMMARY" echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" - [ "$bad" -eq 0 ] else - bad=$((bad+1)) - fi - echo "::endgroup::" - done < <( - find docs src/pages \ - -type f \( -name "*.md" -o -name "*.mdx" \) \ - -print0 2>/dev/null - ) - titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) - { - echo "### Harper summary" - echo "- Files scanned: $total" - echo "- Files with issues: $bad" - echo "- Heading title case violations: $titlecase" - echo "" - echo "### Violations by rule" - echo '```' - grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true - echo '```' - } >> "$GITHUB_STEP_SUMMARY" - echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" - [ "$bad" -eq 0 ] ExpandMemoryShorthands - ExpandDirectory - AnA - NoFrenchSpaces - InflectedVerbAfterTo - CapitalizePersonalPronouns - Dashes - ) - IGNORE_ARGS=() - for rule in "${IGNORED_RULES[@]}"; do - IGNORE_ARGS+=(--ignore "$rule") - done - out="$(mktemp)" - total=0 - bad=0 - while IFS= read -r -d '' file; do - total=$((total+1)) - echo "::group::$file" - if harper-cli lint "${IGNORE_ARGS[@]}" "$file" 2>&1 | tee -a "$out"; then - : - else - bad=$((bad+1)) - fi - echo "::endgroup::" - done < <( - find docs src/pages \ - -type f \( -name "*.md" -o -name "*.mdx" \) \ - -print0 2>/dev/null - ) - titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) - { - echo "### Harper summary" - echo "- Files scanned: $total" - echo "- Files with issues: $bad" - echo "- Heading title case violations: $titlecase" - echo "" - echo "### Violations by rule" - echo '```' - grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true - echo '```' - } >> "$GITHUB_STEP_SUMMARY" - echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" [ "$bad" -eq 0 ] - - - name: Annotate PR with Harper warnings - if: always() - run: | - set -uo pipefail - ONLY_RULES=( - UseTitleCase - RepeatedWords - ) - ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" - while IFS= read -r -d '' file; do - if json_out="$(harper-cli lint $ONLY_ARG --format json "$file" 2>/dev/null)"; then - : - else - printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);esc=lambda s: s.replace('%','%25').replace('\r','%0D').replace('\n','%0A');[print('::warning file='+esc(f.get('file',''))+',line='+str(l.get('line',1))+',col='+str(l.get('column',1))+',title='+esc(l.get('rule','?'))+'::'+esc(l.get('message',''))) for f in d for l in f.get('lints',[])]" || true - fi - done < <( - find docs src/pages \ - -type f \( -name "*.md" -o -name "*.mdx" \) \ - -print0 2>/dev/null - ) From c2337297e87958b386649451d8ed06bb1aaf8b21 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sat, 11 Jul 2026 23:05:21 +0800 Subject: [PATCH 24/37] Refactor Docs Quality workflow for better checks Updated workflow for Docs Quality to improve spelling and grammar checks. --- .github/workflows/docs-quality.yml | 98 +++++++++++++++++------------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 7733d6662a..d34a1d4620 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -1,95 +1,107 @@ name: Docs Quality - on: pull_request: - paths: - - "docs/**/*.md" - - "docs/**/*.mdx" - - "_typos.toml" - - ".github/workflows/docs-quality.yml" - push: - branches: [main] - workflow_dispatch: {} - -permissions: - contents: read - + workflow_dispatch: jobs: typos: name: Spelling (typos-cli) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v6 - uses: crate-ci/typos@master harper: - name: Grammar & headings (Harper) + name: Grammar and Style Check runs-on: ubuntu-latest continue-on-error: true steps: - - uses: actions/checkout@v4 - - - name: Cache harper-cli binary + - name: Checkout + uses: actions/checkout@v6 + - name: Cache Harper CLI id: cache-harper uses: actions/cache@v4 with: - path: ~/.cargo/bin/harper-cli - key: harper-cli-${{ runner.os }}-v1 + path: | + ~/.cargo/bin/harper-cli + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-harper-cli restore-keys: | - harper-cli-${{ runner.os }}- + ${{ runner.os }}-harper-cli - name: Report cache status run: | echo "cache-hit output: '${{ steps.cache-harper.outputs.cache-hit }}'" - if [ -f ~/.cargo/bin/harper-cli ]; then - echo "harper-cli binary present at ~/.cargo/bin/harper-cli" + ls -la ~/.cargo/bin/ 2>&1 || echo "~/.cargo/bin does not exist" + if [ -x ~/.cargo/bin/harper-cli ]; then + echo "RESULT: harper-cli binary present and executable" + ~/.cargo/bin/harper-cli --version || true else - echo "harper-cli binary NOT present -- will build from source" + echo "RESULT: harper-cli binary NOT present -- full reinstall will run" fi - - name: Install harper-cli + - name: Install Harper CLI if: steps.cache-harper.outputs.cache-hit != 'true' run: cargo install --locked --git https://github.com/Automattic/harper.git harper-cli - - name: Lint docs with Harper run: | set -uo pipefail - IGNORED_RULES=( - SpellCheck - OrthographicConsistency - ProperNouns - CompaniesProductsAndTrademarks - GoogleNames MicrosoftNames AmazonNames AzureNames MetaNames - LongSentences Hedging FillerWords - ExpandStandardInputAndOutput ExpandTimeShorthands ExpandMemoryShorthands - ExpandDirectory ExpandArgument ExpandParameter ExpandPointer - ExpandDependencies ExpandControl ExpandAlgorithm ExpandAlloc - ExpandDecl ExpandVulnerability + ONLY_RULES=( + UseTitleCase + RepeatedWords + MergeWords + ItsContraction ) - IGNORE_ARGS=() - for r in "${IGNORED_RULES[@]}"; do IGNORE_ARGS+=(--ignore "$r"); done + ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" out="$(mktemp)" total=0 bad=0 while IFS= read -r -d '' file; do total=$((total+1)) echo "::group::$file" - if harper-cli lint "${IGNORE_ARGS[@]}" "$file" 2>&1 | tee -a "$out"; then + if harper-cli lint $ONLY_ARG "$file" 2>&1 | tee -a "$out"; then : else bad=$((bad+1)) fi echo "::endgroup::" - done < <(find docs \( -name '*.md' -o -name '*.mdx' \) -print0) + done < <( + find docs src/pages \ + -type f \( -name "*.md" -o -name "*.mdx" \) \ + -print0 2>/dev/null + ) titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) { echo "### Harper summary" echo "- Files scanned: $total" echo "- Files with issues: $bad" - echo "- Heading (UseTitleCase) violations: $titlecase" + echo "- Heading title case violations: $titlecase" echo "" echo "### Violations by rule" echo '```' - grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn + grep -oE '\[[A-Za-z]+::[A-Za-z]+\]' "$out" | sort | uniq -c | sort -rn || true echo '```' } >> "$GITHUB_STEP_SUMMARY" echo "== Harper: $bad/$total files with issues; $titlecase UseTitleCase violations ==" [ "$bad" -eq 0 ] + - name: Annotate PR with Harper warnings + if: always() + run: | + set -uo pipefail + ONLY_RULES=( + UseTitleCase + RepeatedWords + MergeWords + ItsContraction + ) + ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" + while IFS= read -r -d '' file; do + if json_out="$(harper-cli lint $ONLY_ARG --format json "$file" 2>/dev/null)"; then + : + else + printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);esc=lambda s: s.replace('%','%25').replace('\r','%0D').replace('\n','%0A');[print('::warning file='+esc(f.get('file',''))+',line='+str(l.get('line',1))+',col='+str(l.get('column',1))+',title='+esc(l.get('rule','?'))+'::'+esc(l.get('message',''))) for f in d for l in f.get('lints',[])]" || true + fi + done < <( + find docs src/pages \ + -type f \( -name "*.md" -o -name "*.mdx" \) \ + -print0 2>/dev/null + ) From 0b602a1b3c1f372fbae2851425896433ee46a026 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sat, 11 Jul 2026 23:12:51 +0800 Subject: [PATCH 25/37] Add test heading to harpertestfile.md --- docs/hpc/harpertestfile.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/hpc/harpertestfile.md diff --git a/docs/hpc/harpertestfile.md b/docs/hpc/harpertestfile.md new file mode 100644 index 0000000000..7cc3f855c7 --- /dev/null +++ b/docs/hpc/harpertestfile.md @@ -0,0 +1 @@ +## this is a test heading From 89ae26d0dcb5c4aad0a987969476ff03c524efe3 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sat, 11 Jul 2026 23:16:00 +0800 Subject: [PATCH 26/37] Delete docs/hpc/harpertestfile.md --- docs/hpc/harpertestfile.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 docs/hpc/harpertestfile.md diff --git a/docs/hpc/harpertestfile.md b/docs/hpc/harpertestfile.md deleted file mode 100644 index 7cc3f855c7..0000000000 --- a/docs/hpc/harpertestfile.md +++ /dev/null @@ -1 +0,0 @@ -## this is a test heading From 7734503969d4c5372ac27cd55667871081b90fb4 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sat, 11 Jul 2026 23:28:02 +0800 Subject: [PATCH 27/37] Create harpertestfile.md --- docs/hpc/harpertestfile.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/hpc/harpertestfile.md diff --git a/docs/hpc/harpertestfile.md b/docs/hpc/harpertestfile.md new file mode 100644 index 0000000000..7cc3f855c7 --- /dev/null +++ b/docs/hpc/harpertestfile.md @@ -0,0 +1 @@ +## this is a test heading From 41fa0902e04e31341655401419a0523fbf075cdc Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sun, 12 Jul 2026 09:59:08 +0800 Subject: [PATCH 28/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index d34a1d4620..ad28e8f42f 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -65,9 +65,7 @@ jobs: fi echo "::endgroup::" done < <( - find docs src/pages \ - -type f \( -name "*.md" -o -name "*.mdx" \) \ - -print0 2>/dev/null + find docs/hpc/harpertestfile.md -type f -print0 2>/dev/null ) titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) { From 4671b3aaab4c6ec30acd7adff19ea67d5b153f92 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:27:19 +0800 Subject: [PATCH 29/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index ad28e8f42f..46007b8674 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -99,7 +99,5 @@ jobs: printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);esc=lambda s: s.replace('%','%25').replace('\r','%0D').replace('\n','%0A');[print('::warning file='+esc(f.get('file',''))+',line='+str(l.get('line',1))+',col='+str(l.get('column',1))+',title='+esc(l.get('rule','?'))+'::'+esc(l.get('message',''))) for f in d for l in f.get('lints',[])]" || true fi done < <( - find docs src/pages \ - -type f \( -name "*.md" -o -name "*.mdx" \) \ - -print0 2>/dev/null + find docs/hpc/harpertestfile.md -type f -print0 2>/dev/null ) From c47a7958596a7d5f9643054970770c8bb8d6d7f8 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:31:28 +0800 Subject: [PATCH 30/37] Delete docs/hpc/harpertestfile.md --- docs/hpc/harpertestfile.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 docs/hpc/harpertestfile.md diff --git a/docs/hpc/harpertestfile.md b/docs/hpc/harpertestfile.md deleted file mode 100644 index 7cc3f855c7..0000000000 --- a/docs/hpc/harpertestfile.md +++ /dev/null @@ -1 +0,0 @@ -## this is a test heading From db0f302361910b78cee808679560c4b5289b3e0a Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:32:04 +0800 Subject: [PATCH 31/37] Add test file for HPC documentation --- docs/hpc/testfile.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/hpc/testfile.md diff --git a/docs/hpc/testfile.md b/docs/hpc/testfile.md new file mode 100644 index 0000000000..5da87ed034 --- /dev/null +++ b/docs/hpc/testfile.md @@ -0,0 +1 @@ +## test file From 03374318c39fff4b85fe5dcd905073003bbd9da8 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:37:54 +0800 Subject: [PATCH 32/37] Rename testfile.md to harpertestfile.md --- docs/hpc/{testfile.md => harpertestfile.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/hpc/{testfile.md => harpertestfile.md} (100%) diff --git a/docs/hpc/testfile.md b/docs/hpc/harpertestfile.md similarity index 100% rename from docs/hpc/testfile.md rename to docs/hpc/harpertestfile.md From 68e2f9be2e8b9ca7ca94db1849c7a7423275bdba Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Sun, 12 Jul 2026 10:53:10 +0800 Subject: [PATCH 33/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 46007b8674..36851f8035 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -96,7 +96,7 @@ jobs: if json_out="$(harper-cli lint $ONLY_ARG --format json "$file" 2>/dev/null)"; then : else - printf '%s' "$json_out" | python3 -c "import json,sys;d=json.load(sys.stdin);esc=lambda s: s.replace('%','%25').replace('\r','%0D').replace('\n','%0A');[print('::warning file='+esc(f.get('file',''))+',line='+str(l.get('line',1))+',col='+str(l.get('column',1))+',title='+esc(l.get('rule','?'))+'::'+esc(l.get('message',''))) for f in d for l in f.get('lints',[])]" || true + printf '%s' "$json_out" | FILE="$file" python3 -c "import json,sys,os;d=json.load(sys.stdin);fp=os.environ['FILE'];esc=lambda s: s.replace('%','%25').replace('\r','%0D').replace('\n','%0A');[print('::warning file='+esc(fp)+',line='+str(l.get('line',1))+',col='+str(l.get('column',1))+',title='+esc(l.get('rule','?'))+'::'+esc(l.get('message',''))) for f in d for l in f.get('lints',[])]" || true fi done < <( find docs/hpc/harpertestfile.md -type f -print0 2>/dev/null From 6a481c528c53e55e587a7330fceda1cf0c4a7d83 Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Tue, 14 Jul 2026 11:53:35 +0800 Subject: [PATCH 34/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index 36851f8035..d11f294ec8 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -65,7 +65,9 @@ jobs: fi echo "::endgroup::" done < <( - find docs/hpc/harpertestfile.md -type f -print0 2>/dev/null + find docs src/pages \ + -type f \( -name "*.md" -o -name "*.mdx" \) \ + -print0 2>/dev/null ) titlecase=$(grep -c 'Capitalization::UseTitleCase' "$out" || true) { @@ -99,5 +101,7 @@ jobs: printf '%s' "$json_out" | FILE="$file" python3 -c "import json,sys,os;d=json.load(sys.stdin);fp=os.environ['FILE'];esc=lambda s: s.replace('%','%25').replace('\r','%0D').replace('\n','%0A');[print('::warning file='+esc(fp)+',line='+str(l.get('line',1))+',col='+str(l.get('column',1))+',title='+esc(l.get('rule','?'))+'::'+esc(l.get('message',''))) for f in d for l in f.get('lints',[])]" || true fi done < <( - find docs/hpc/harpertestfile.md -type f -print0 2>/dev/null + find docs src/pages \ + -type f \( -name "*.md" -o -name "*.mdx" \) \ + -print0 2>/dev/null ) From 63a6d5df78b053e1d01a5f4f829daad413d3bc1f Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Tue, 14 Jul 2026 17:56:00 +0800 Subject: [PATCH 35/37] Update docs-quality.yml --- .github/workflows/docs-quality.yml | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docs-quality.yml b/.github/workflows/docs-quality.yml index d11f294ec8..54d82ba5fb 100644 --- a/.github/workflows/docs-quality.yml +++ b/.github/workflows/docs-quality.yml @@ -52,13 +52,24 @@ jobs: ItsContraction ) ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" + mdxtmp="$(mktemp -d)" out="$(mktemp)" total=0 bad=0 while IFS= read -r -d '' file; do total=$((total+1)) + case "$file" in + *.mdx) + target="$mdxtmp/${file}.md" + mkdir -p "$(dirname "$target")" + cp "$file" "$target" + ;; + *) + target="$file" + ;; + esac echo "::group::$file" - if harper-cli lint $ONLY_ARG "$file" 2>&1 | tee -a "$out"; then + if harper-cli lint $ONLY_ARG "$target" 2>&1 | tee -a "$out"; then : else bad=$((bad+1)) @@ -94,8 +105,19 @@ jobs: ItsContraction ) ONLY_ARG="--only $(IFS=,; echo "${ONLY_RULES[*]}")" + mdxtmp="$(mktemp -d)" while IFS= read -r -d '' file; do - if json_out="$(harper-cli lint $ONLY_ARG --format json "$file" 2>/dev/null)"; then + case "$file" in + *.mdx) + target="$mdxtmp/${file}.md" + mkdir -p "$(dirname "$target")" + cp "$file" "$target" + ;; + *) + target="$file" + ;; + esac + if json_out="$(harper-cli lint $ONLY_ARG --format json "$target" 2>/dev/null)"; then : else printf '%s' "$json_out" | FILE="$file" python3 -c "import json,sys,os;d=json.load(sys.stdin);fp=os.environ['FILE'];esc=lambda s: s.replace('%','%25').replace('\r','%0D').replace('\n','%0A');[print('::warning file='+esc(fp)+',line='+str(l.get('line',1))+',col='+str(l.get('column',1))+',title='+esc(l.get('rule','?'))+'::'+esc(l.get('message',''))) for f in d for l in f.get('lints',[])]" || true From 2fa8f0bfb250c8f58df52347f64d628d7c28151a Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Thu, 16 Jul 2026 00:39:20 +0800 Subject: [PATCH 36/37] Update harpertestfile.md --- docs/hpc/harpertestfile.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/hpc/harpertestfile.md b/docs/hpc/harpertestfile.md index 5da87ed034..48842120b8 100644 --- a/docs/hpc/harpertestfile.md +++ b/docs/hpc/harpertestfile.md @@ -1 +1,2 @@ ## test file +## `rsync` and `rclone` From 06bdbc506398e91dc539a10877e97d22f1e5975a Mon Sep 17 00:00:00 2001 From: Amanda-dong <159391549+Amanda-dong@users.noreply.github.com> Date: Thu, 16 Jul 2026 00:48:19 +0800 Subject: [PATCH 37/37] Update heading style in harpertestfile.md --- docs/hpc/harpertestfile.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hpc/harpertestfile.md b/docs/hpc/harpertestfile.md index 48842120b8..c89293b339 100644 --- a/docs/hpc/harpertestfile.md +++ b/docs/hpc/harpertestfile.md @@ -1,2 +1,2 @@ ## test file -## `rsync` and `rclone` +## `rsync` And `rclone`