Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 32 additions & 43 deletions .github/workflows/no-emdash.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,28 @@ name: Em-dash gate
# `docs-content/` pages that publish to docs.cosyte.com. A sweep without the gate grows
# back; a gate without the sweep would have red-flagged CI on arrival. Both are one commit.
#
# WHAT ACTUALLY SCANS, AND WHERE THE RULE LIVES. `pnpm check:no-emdash`, which is this
# repository's own gate script. The jobs below delegate the plumbing (checkout, pnpm,
# Node) to the shared gate workflow, and that workflow carries no pattern, no allow-list
# and no file selection of its own: it prepares the tree, runs the command, and lets the
# command's exit status decide the job. So the rule and every measurement above stay in
# this repository, and only the harness is shared.
#
# TWO CONTEXTS, NOT ONE, AND THE JOB ID IS LOAD-BEARING. A called job's check run is named
# `<caller job id> / <inner job id>`, so the job id `no-emdash` below publishes
# `no-emdash / tracked-files` and `no-emdash / messages`. A branch ruleset binds to those
# exact strings: renaming the job detaches the requirement with no error anywhere, and a
# required context nothing emits blocks every pull request. Do not rename it.
#
# `no-emdash / tracked-files` is the half that is safe to require and the one that blocks
# a merge. `no-emdash / messages` runs, reds its own context, and is deliberately NOT
# required: Dependabot composes a pull request body out of upstream release notes, em
# dashes included, and a gate that fails on someone else's clock becomes a tax. The
# detection is unchanged either way; only what blocks is narrowed.
#
# WHY A SEPARATE WORKFLOW, and not a job in ci.yml:
#
# The reusable pipeline is not an option. astm's `ci` job calls
# The shared ci pipeline is not an option. astm's `ci` job calls
# cosyte/.github/.github/workflows/ci.yml@main, which runs a fixed ladder and no
# arbitrary repo script.
#
Expand All @@ -24,8 +43,7 @@ name: Em-dash gate
# typo in a PR description is a large cost for no extra safety. Same call hl7 and
# website made, for the same reason.
#
# Run it locally with `pnpm check:no-emdash`, which is also on `scripts/verify.sh astm`'s
# ladder in the meta-repo.
# Run it locally with `pnpm check:no-emdash`.

on:
push:
Expand All @@ -39,45 +57,16 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
# The check-run context prefix. See the note above before touching this id.
no-emdash:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
# Full history: the commit-message step below reads the PR's commit range,
# and the default shallow clone does not contain the base commit.
fetch-depth: 0

- name: Check tracked files
run: bash scripts/check-no-emdash.sh

# The rule names commit messages explicitly, and a squash merge composes its
# message from the PR title, the PR body, and the branch commits, so all three are
# checked. Pull requests only: on a push to main the message is already written,
# and this gate exists to stop it landing.
- name: Check PR title, body, and commit messages
if: github.event_name == 'pull_request'
env:
PR_TITLE: ${{ github.event.pull_request.title }}
PR_BODY: ${{ github.event.pull_request.body }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
# Collect first, scan second, and set the shell options here rather than trust
# the runner's default: piping the collection straight into the scanner would
# hide a failed `git log` (a rewritten base commit, or a future edit that drops
# fetch-depth) behind a clean title and body, and the gate would print OK over
# commits it never read. The title and body arrive through env and are never
# interpolated into the script, so a PR description cannot inject shell.
set -euo pipefail
{
printf '%s\n' "$PR_TITLE"
printf '%s\n' "$PR_BODY"
git log --format=%B "$BASE_SHA..$HEAD_SHA"
} > "$RUNNER_TEMP/pr-messages.txt"
bash scripts/check-no-emdash.sh --stdin "the PR title, body, or commit messages" \
< "$RUNNER_TEMP/pr-messages.txt"
# Pinned to the 40 character commit, not to the tag beside it: a tag can be moved
# or deleted by anyone who gains write access to the workflow's repository, so a
# tag is not an immutable reference and is not a pin. The trailing comment is the
# published reference that commit was released as, so the release note stays
# findable from here.
uses: cosyte/.github/.github/workflows/gate-no-emdash.yml@84ecccd771cbc9c1ece003a3f8ff61415360395b # workflows-2026-09-18-84ecccd771cb
# No more than the scan needs. A called workflow's GITHUB_TOKEN can only be
# downgraded by its caller, and this gate reads the tree and nothing else.
permissions:
contents: read
50 changes: 27 additions & 23 deletions .github/workflows/no-internal-refs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,21 @@ name: Public-surface gate
# SUCH GATE AT ALL until this workflow landed, which is why the class had regrown into the
# doc comments of fifteen source files and into the published `dist/index.d.ts`.
#
# WHY A SEPARATE WORKFLOW, and not a job in ci.yml. The reusable pipeline is not an option:
# WHAT ACTUALLY SCANS, AND WHERE THE RULE LIVES. `pnpm check:no-internal-refs`, which is
# this repository's own checker. The job below delegates the plumbing (checkout, pnpm,
# Node) to the shared gate workflow, which carries no pattern, no allow-list and no file
# selection of its own: it prepares the tree, runs the command, and lets the command's
# exit status decide the job. The detection rules, the self-tests and the known project
# prefixes all stay here, because what counts as a project prefix and what counts as a
# domain designator is a property of this package.
#
# THE JOB ID IS LOAD-BEARING. A called job's check run is named
# `<caller job id> / <inner job id>`, so the job id `no-internal-refs` below publishes
# `no-internal-refs / public-surface`, which is the context a branch ruleset must require.
# Renaming the job detaches that requirement with no error anywhere, and a required
# context nothing emits blocks every pull request.
#
# WHY A SEPARATE WORKFLOW, and not a job in ci.yml. The shared ci pipeline is not an option:
# this repo's `ci` job calls cosyte/.github/.github/workflows/ci.yml@main, which runs a
# fixed ladder and no arbitrary repo script. Adding this there would also flip every other
# caller red on its next run, and remediating each repo is its own deliberate piece of work.
Expand All @@ -40,8 +54,7 @@ name: Public-surface gate
# workflow name instead blocks every pull request permanently, because no check run ever
# reports under it. That trap has fired live in a sibling repo on this exact workflow.
#
# Run it locally with `pnpm check:no-internal-refs`, which is also on the meta-repo's
# `scripts/verify.sh astm` ladder.
# Run it locally with `pnpm check:no-internal-refs`.

on:
push:
Expand All @@ -53,25 +66,16 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
# The job id is the check-run context name a branch ruleset requires. Renaming it
# silently detaches the required check, so the ruleset stops protecting anything while
# still looking configured. Rename both together or neither.
# The check-run context prefix. See the note above before touching this id.
no-internal-refs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

# The script self-tests before it reports: it proves each rule still matches its own
# positive sample AND still lets through the reference material it was most likely to
# destroy (`ASTM-E1394`, `CLSI-LIS01`, `LIS02-A2`, the `SPEC-7` / `ACC-42` example
# ids, `ICD-10-CM`, a Phase III trial, and E1381's own establishment / transfer /
# termination protocol phases). It also asserts that no rule matches a BARE section
# citation, so closing that deliberate hole has to be a decision rather than an
# accident. It refuses to print OK from a scan that did not read all of its input.
# No `|| true`, no `continue-on-error`: a check that cannot fail is documentation.
- name: Check the public surface
run: bash scripts/check-no-internal-refs.sh
# Pinned to the 40 character commit, not to the tag beside it: a tag can be moved
# or deleted by anyone who gains write access to the workflow's repository, so a
# tag is not an immutable reference and is not a pin. The trailing comment is the
# published reference that commit was released as, so the release note stays
# findable from here.
uses: cosyte/.github/.github/workflows/gate-no-internal-refs.yml@84ecccd771cbc9c1ece003a3f8ff61415360395b # workflows-2026-09-18-84ecccd771cb
# No more than the scan needs. A called workflow's GITHUB_TOKEN can only be
# downgraded by its caller, and this gate reads the tree and nothing else.
permissions:
contents: read
Loading