diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9cccfe2..9ca90cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -662,14 +662,17 @@ jobs: # any specific sensitive value. Broad by design — belt-and- # suspenders over local hygiene. PATTERNS=( - # Absolute home paths (macOS, Linux, Windows). + # Absolute home paths (macOS, Linux, Windows). The two patterns + # that end in a backslash are double-quoted (each `\\` of the + # regex is written `\\\\`) because shellcheck reads a single- + # quoted string ending in `\\'` as a botched `\'` (SC1003). '/Users/[a-z][a-z0-9._-]+/' '/home/[a-z][a-z0-9._-]+/' - 'C:\\Users\\[a-z][a-z0-9._-]+\\' + "C:\\\\Users\\\\[a-z][a-z0-9._-]+\\\\" # Autodesk build-server paths baked into released DLLs. 'F:\\Ship\\[0-9]{4}_' # Employee OneDrive authoring paths. - 'OneDrive - Autodesk\\[^\\]*\\' + "OneDrive - Autodesk\\\\[^\\\\]*\\\\" ) failed=0 for p in "${PATTERNS[@]}"; do diff --git a/.github/workflows/docs-rs.yml b/.github/workflows/docs-rs.yml index 525601b..3c4ea20 100644 --- a/.github/workflows/docs-rs.yml +++ b/.github/workflows/docs-rs.yml @@ -89,7 +89,8 @@ jobs: set -euo pipefail PUBS=$(grep -rnE '^\s*pub fn ' src/ --include='*.rs' \ | grep -vE '^src/bin/' \ - | wc -l | tr -d ' ') + | awk 'END { print NR }') + mapfile -t SOURCES < <(find src -name '*.rs' | grep -v '^src/bin/') # Count `pub fn` lines whose immediately-preceding non-attribute, # non-blank line is a `///` doc comment. We use awk to walk the # concatenated source looking backwards. @@ -103,7 +104,7 @@ jobs: /^[[:space:]]*$/ { next } # skip blank lines { prev_doc=0 } END { print docs+0 } - ' $(find src -name '*.rs' | grep -v '^src/bin/')) + ' "${SOURCES[@]}") echo "pub fn count: ${PUBS}" echo "pub fn documented: ${DOCS}" if [ "$PUBS" -eq 0 ]; then diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ac4e872..339e159 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -193,15 +193,21 @@ jobs: # -------------------------------------------------------------------- # Python bindings (PyO3) — intentionally disabled until `python_stubs.rs` - # graduates from a placeholder. When that lands, flip `if: false` to the - # real tag condition and wire maturin. Leaving the scaffold in place so - # the work item is visible in the workflow graph instead of a TODO file. + # graduates from a placeholder. When that lands, replace the `if:` below + # with the real tag condition and wire maturin. Leaving the scaffold in + # place so the work item is visible in the workflow graph instead of a + # TODO file. actionlint rejects a literal `if: false` (#269), so the job + # is held off by a condition no trigger of this workflow can satisfy: + # this workflow runs on tag pushes and workflow_dispatch only, and no + # event is named `disabled`. # Tracked alongside #420 / Phase 13 WASM/Python roadmap. # -------------------------------------------------------------------- publish-pypi: name: Publish Python wheels to PyPI (DISABLED) needs: verify - if: false # flip to a SemVer-style condition once PyO3 work ships + # Never true on purpose, and not a literal `false`: actionlint rejects a + # constant condition (#269). Do not simplify this back to `if: false`. + if: github.event_name == 'disabled' # replace with a SemVer-style condition once PyO3 work ships runs-on: ${{ matrix.os }} strategy: matrix: diff --git a/CHANGELOG.md b/CHANGELOG.md index 287fbbb..f7c7bba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -179,7 +179,7 @@ What the writer needed from the decoders, kept where they were read and dropped: No library behaviour changes in this entry. -- **CI gates.** Perf benches the PR's merge-base and the PR in one job on one host, instead of comparing against a baseline cached from another runner, which had measured hardware and flagged PRs that touched no benchmarked code (#217). A Spec coverage job runs `tools/ci/spec_coverage.py`, so `docs/spec-coverage.md` keeps one row for every section of ODA spec v5.4.1 and never drifts from `docs/data/spec-coverage.tsv` (#219). The PII guard also refuses merge-conflict markers (#309), and the Spec coverage job refuses ARCHITECTURE.md sections that repeat or skip a letter (#334). The nightly fuzz run covers its whole budget and fails on a crash (#232). Every cargo workflow sets `CARGO_NET_RETRY=10` (#268), and the wasm-pack install retries up to five times on a transient download failure (#342). `main` requires Corpus and Spec coverage (#292); docs/maintaining.md describes the `main-protection` ruleset, with no bypass, as it is (#220). `tools/maintainer/clean_caches.py`, which `audit.py` already pointed to, removes the Actions caches of closed pull requests and the superseded ones per key family (#361), the cache having stood at 9.95 GB of its 10 GB. +- **CI gates.** Perf benches the PR's merge-base and the PR in one job on one host, instead of comparing against a baseline cached from another runner, which had measured hardware and flagged PRs that touched no benchmarked code (#217). A Spec coverage job runs `tools/ci/spec_coverage.py`, so `docs/spec-coverage.md` keeps one row for every section of ODA spec v5.4.1 and never drifts from `docs/data/spec-coverage.tsv` (#219). The PII guard also refuses merge-conflict markers (#309), and the Spec coverage job refuses ARCHITECTURE.md sections that repeat or skip a letter (#334). The nightly fuzz run covers its whole budget and fails on a crash (#232). Every cargo workflow sets `CARGO_NET_RETRY=10` (#268), and the wasm-pack install retries up to five times on a transient download failure (#342). `main` requires Corpus and Spec coverage (#292); docs/maintaining.md describes the `main-protection` ruleset, with no bypass, as it is (#220). `tools/maintainer/clean_caches.py`, which `audit.py` already pointed to, removes the Actions caches of closed pull requests and the superseded ones per key family (#361), the cache having stood at 9.95 GB of its 10 GB. The five actionlint findings on `main` are cleared without changing what a workflow does (#269): the PII guard's backslash-ended patterns are double-quoted, the docs.rs docstring ratio counts with `awk` and quoted arrays, and `publish-pypi` in `release.yml` stays off through a condition that is never true rather than a literal `if: false`, which actionlint rejects. - **Merge train.** `tools/maintainer/train/train.sh` lands queued decoder PRs one at a time, regenerating the generated files (`tools/corpus/baseline.tsv`, `docs/spec-coverage.md`, the spec-example fixtures) and renumbering colliding ARCHITECTURE.md sections instead of leaving every open PR stale after each merge (#298). It ratchets the DXF oracle baseline as well (#300), defers a PR whose build is refused a governor lease instead of dropping it from the queue (#304), resolves both-sides appends to CLEANROOM.md (#327), never leaves auto-merge on a PR it stops landing (#336), resets its worktree before each checkout (#338), ignores oracle rows the PR itself renamed (#344) and, after main carried three `7n` sections, numbers ARCHITECTURE.md's newer sections in landing order (#322). - **Documentation.** CLAUDE.md for coding agents and contributor docs brought up to date, including the decoder registration steps and the rule that evidence is real-file, not unit tests (#218, #257); a 10-minute contributor quickstart at the top of CONTRIBUTING.md (#18); a CLEANROOM.md entry that a class layout the spec never prints is derived from AutoCAD's own DWG and its DXF export, accepted only when it closes every record's boundary on every release and every decoded value equals the twin's group (#321); AGENTS.md gives a reviewer the clean-room rule (#369). - **Fixtures and benchmarks.** `examples/build_fixtures` writes the four canonical R2004-family fixtures, five entities each, byte-deterministically, so the coverage-smoke job has a corpus to run against instead of skipping, with a 95 % floor on the decoded ratio and a noise floor for the Criterion job (#19). diff --git a/RELEASE.md b/RELEASE.md index 203f5ca..55155b7 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -149,9 +149,12 @@ entirely and produce a draft GitHub release marked `prerelease`. contributors can run `git-cliff --tag vX.Y.Z --prepend CHANGELOG.md` as a starting point, but the final edit is hand-curated. - Python wheels are not shipped yet. The `publish-pypi` job in - `release.yml` is gated off with `if: false` until the PyO3 bindings - planned in [`docs/python.md`](docs/python.md) replace the - `src/python_stubs.rs` placeholder. + `release.yml` is gated off by a condition that is never true + (`github.event_name == 'disabled'`; no trigger of the workflow has + that name) until the PyO3 bindings planned in + [`docs/python.md`](docs/python.md) replace the `src/python_stubs.rs` + placeholder. The condition is not a literal `if: false` because + actionlint flags a constant condition (#269). ## Yanking a release