measure the shortest line window that decides a seam #81
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| # One job per QUESTION, not one per command. `gates` answers "is this | |
| # tree well-formed?" — everything that needs no other revision, so a | |
| # fresh clone answers it. `differential` answers "did this change | |
| # behaviour?" — everything that does, which is why it needs the whole | |
| # history and a base commit. | |
| # | |
| # Every gate carries `if: ${{ !cancelled() }}` so one failing gate | |
| # never hides the others — a push that breaks lint AND a minimum | |
| # should say so in one run, not across two. | |
| jobs: | |
| gates: | |
| name: Gates (head only) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: oven-sh/setup-bun@v2 | |
| - run: bun install --frozen-lockfile | |
| - run: bun run check | |
| if: ${{ !cancelled() }} | |
| - run: bun run lint | |
| if: ${{ !cancelled() }} | |
| - run: bun run fmt:check | |
| if: ${{ !cancelled() }} | |
| - run: bun run build | |
| if: ${{ !cancelled() }} | |
| # The suite, under v8 line coverage, with each file's RECORDED | |
| # MINIMUM coverage checked afterwards — ONE suite run, not two. | |
| # Measured at 2.8s plain against 4.0s with coverage on 8,577 | |
| # tests, so the check costs about a second and belongs in the | |
| # blocking job rather than in a step of its own. The mutation | |
| # half of the same minimums file is checked by `bun run mutate`, | |
| # which is ~11 minutes and stays manual. | |
| - run: bun run coverage | |
| if: ${{ !cancelled() }} | |
| # The scorecard, head-only: thirteen absolute gates plus the shape | |
| # census's five rules, in about two seconds, needing no base and no | |
| # network. It has been enforceable since the day it was written | |
| # and was enforced by nobody; this line is the whole point of the | |
| # workstream that added it. | |
| - run: bun run metrics | |
| if: ${{ !cancelled() }} | |
| # The exhaustive depth-5 list-shape sweep — 111,121 documents, | |
| # each formatted twice and rendered on both sides against a | |
| # 158-entry allowlist, ~30s. It used to ride inside `bun run | |
| # test`, where it was 25.6s of a 26.1s suite; it left the default | |
| # suite ON CONDITION that it became a blocking step here and the | |
| # prelude to every mutation run, so nothing about what is | |
| # enforced changed. Head-only and needs no base, so it belongs in | |
| # this job. | |
| - run: bun run test:deeply-nested-lists | |
| if: ${{ !cancelled() }} | |
| # Our AST's BLOCK STRUCTURE against the oracle's, over the | |
| # conformance corpus and the depth-4 sweep product, gated on | |
| # scripts/block-structure-corpus.json and | |
| # scripts/block-structure-sweep.json. About a second, head-only | |
| # and needing no base, so it sits beside the deep sweep. The | |
| # default suite runs the CORPUS half only; this step is what | |
| # covers the SWEEP half, where 931 of the 932 divergences no | |
| # other net sees actually live. `--depth 5` is available for | |
| # anyone who wants the deeper product: it adds 16 signatures and | |
| # no new root cause. A passing run prints an Asciidoctor object | |
| # dump on stderr for one corpus document; see docs/harnesses.md. | |
| - run: bun run block-structure | |
| if: ${{ !cancelled() }} | |
| # Every source citation in a comment - a Ruby file and line, or a | |
| # line of the oracle build - against the file it names. Reads | |
| # vendor/asciidoctor-ruby/ and node_modules only, takes under a | |
| # second, needs no base: a head-only gate like the two above. It | |
| # is its own step rather than a metrics row because it is its own | |
| # question with its own exit-code contract, exactly as | |
| # block-structure is. | |
| - run: bun run citation-check | |
| if: ${{ !cancelled() }} | |
| # The other direction: every `<file>:<line>` this repository | |
| # writes about ITSELF - the `what` field of a score-minimums | |
| # exception, the coverage-deferral comments in eslint.config.js - | |
| # against the line it names, plus every `src/...ts` path a `src` | |
| # comment names against a file that exists. Reads the working | |
| # tree only, takes well under a second, needs no base: a | |
| # head-only gate beside the one above, and its own question with | |
| # its own exit-code contract for the same reason that one is. | |
| - run: bun run internal-citations | |
| if: ${{ !cancelled() }} | |
| differential: | |
| name: Differential (vs base) | |
| runs-on: ubuntu-latest | |
| # FIRST ITERATION ONLY. The differential harnesses have never run | |
| # on this machine shape, and a harness whose own footing is untested | |
| # must not be able to block a merge on its first day. Flipping this | |
| # to blocking is a one-line change, and the trigger for it is | |
| # stated: three consecutive green runs on merges to main. | |
| continue-on-error: true | |
| steps: | |
| # `fetch-depth: 0` because every harness here materializes | |
| # another revision with `git archive`, and a shallow clone does | |
| # not have one. | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - uses: oven-sh/setup-bun@v2 | |
| - run: bun install --frozen-lockfile | |
| # The base is a SHA this workflow computes, never a branch name | |
| # and never `github.event.pull_request.base.sha`. Two reasons, | |
| # both learned here: this repository is jj-managed with a | |
| # colocated `.git` and is routinely on no branch at all, so | |
| # nothing may key on one; and the PR event's base sha is the base | |
| # branch's TIP, not the merge base, so a long-lived branch would | |
| # be diffed against commits it never contained. | |
| - name: Resolve the base revision | |
| id: base | |
| run: | | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| git fetch --no-tags origin "${{ github.base_ref }}" | |
| base=$(git merge-base FETCH_HEAD HEAD) | |
| else | |
| base=$(git rev-parse HEAD^) | |
| fi | |
| echo "sha=$base" >> "$GITHUB_OUTPUT" | |
| echo "base is $base" | |
| # Serialized inside ONE job on purpose. Each of these four | |
| # materializes the base into $TMPDIR, and three of them run | |
| # `bun install --frozen-lockfile` in it; run as parallel jobs | |
| # they would each pay that install, and run as parallel steps | |
| # they would pay it concurrently on one runner's disk. | |
| # | |
| # Parity runs the ledger gate: any case whose formatted output or | |
| # AST differs from the base must be declared by a | |
| # "Parity-Diff: <family> <id>" trailer in the message of a commit | |
| # in base..HEAD. Declarations expire on their own - a commit that | |
| # moved bytes leaves the range as soon as the base advances past | |
| # it - so there is no file to reset. See docs/harnesses.md. | |
| - name: parity — every corpus document and fixture, bytes and AST | |
| if: ${{ !cancelled() && steps.base.outputs.sha != '' }} | |
| run: | |
| bun run parity -- --base "${{ steps.base.outputs.sha }}" | |
| --expected-diffs-trailers HEAD | |
| - name: shape-diff — the standing grid, with per-diff render proofs | |
| if: ${{ !cancelled() && steps.base.outputs.sha != '' }} | |
| run: bun run shape-diff -- --base "${{ steps.base.outputs.sha }}" | |
| - name: shape-diff — the heading-adjacency grid | |
| if: ${{ !cancelled() && steps.base.outputs.sha != '' }} | |
| run: | |
| bun run shape-diff -- --base "${{ steps.base.outputs.sha }}" --grid | |
| heading-adjacency | |
| - name: shape-diff — the list-run grid | |
| if: ${{ !cancelled() && steps.base.outputs.sha != '' }} | |
| run: | |
| bun run shape-diff -- --base "${{ steps.base.outputs.sha }}" --grid | |
| list-run | |
| # The four generated domains the list-shape sweep's alphabet | |
| # cannot spell - a hard-break line, and constructs broken across | |
| # two source lines - as SET DIFFERENCES on both measures, so a | |
| # domain that fixes as many documents as it breaks cannot report | |
| # the same count and pass. About ten seconds over 12,170 | |
| # documents, and the only step here that can see a reflow hold | |
| # rule regress. See docs/harnesses.md. | |
| - name: probe-domains — the shape classes every other net is blind to | |
| if: ${{ !cancelled() && steps.base.outputs.sha != '' }} | |
| run: bun run probe-domains -- --base "${{ steps.base.outputs.sha }}" | |
| - name: metrics — the ratchets | |
| if: ${{ !cancelled() && steps.base.outputs.sha != '' }} | |
| run: bun run metrics -- --base "${{ steps.base.outputs.sha }}" |