From 2e8c92a8d64964921192831a582d81dafa3f5594 Mon Sep 17 00:00:00 2001 From: Brian Yahn Date: Sat, 1 Aug 2026 10:15:49 +0000 Subject: [PATCH 1/3] Retire the architecture experiment job change_coupling.rb joins cycle_report.rb and reach_through_report.rb as a WIP experiment that is not run in CI, which leaves the Architecture SARIF job with nothing to do, so it goes too. All three were introduced as "WIP anti-pattern experiment tools" (beb2fe8cf), none graduated into a gem, and none had its findings shown to be worth acting on. The job was spending a full runner - checkout, bundle, ruby setup - on 0.83s of work, and arch-change-coupling had no consumer beyond the SARIF upload itself. If change coupling earns its place it belongs in SlopCop::Bugspots, not in SlopCop::Constraints; the tool header records why. Nothing depended on this job and no aggregator listed it. The three tools and their tests stay in the tree. Co-authored-by: Codex --- .github/workflows/ci.yml | 57 -------------------------- gems/gigasail/tools/change_coupling.rb | 14 +++++++ 2 files changed, 14 insertions(+), 57 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4218dbabb..81c1c1d4b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1629,63 +1629,6 @@ jobs: if-no-files-found: error retention-days: 7 - architecture-sarif: - # Cross-module change coupling (gigasail/tools/change_coupling.rb), - # advisory (warning/note level): it annotates PRs and feeds the Lineage - # ledger via SARIF, it does not block merges. - # - # cycle_report.rb and reach_through_report.rb are deliberately NOT run - # here. Both are WIP experiments (beb2fe8cf, "WIP anti-pattern experiment - # tools") and both cost a whole-corpus FactMine projection - together they - # were the entire runtime of this job. - # - # reach_through additionally cannot model package-scoped languages: it - # derives owners per file, so two files in one Go package read as a - # cross-module private call, which is what its 81 self-quarantined - # "suspect" findings are. - # - # cycle_report is the sounder of the two - its four findings here are real - # cycles, not artifacts - but it is off pending a measurement of whether - # those findings are worth acting on. If they are, it belongs inside - # Espalier as a library check next to privacy_analyzer.rb, not as a tool - # shelling out to a whole-corpus projection. The tools and their tests stay - # in the tree meanwhile. - name: Architecture SARIF - runs-on: ubuntu-latest - timeout-minutes: 15 - needs: - - changes - if: ${{ always() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && (needs.changes.outputs.run_gems == 'true' || needs.changes.outputs.run_src == 'true') }} - permissions: - contents: read - security-events: write - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ env.RUBY_VERSION }} - bundler-cache: true - - name: Generate architecture SARIFs - run: | - git fetch origin "+${{ github.event.pull_request.base.ref }}:refs/remotes/origin/${{ github.event.pull_request.base.ref }}" - mkdir -p tmp - base="origin/${{ github.event.pull_request.base.ref }}" - ruby gems/gigasail/tools/change_coupling.rb . 8 \ - --base="$base" --sarif=tmp/arch-change-coupling.sarif - - name: Upload change-coupling SARIF - uses: github/codeql-action/upload-sarif@v4 - with: - sarif_file: tmp/arch-change-coupling.sarif - category: architecture-change-coupling - - uses: actions/upload-artifact@v4 - with: - name: architecture-sarifs - path: tmp/arch-*.sarif - if-no-files-found: error - retention-days: 7 - # Keep each SARIF producer in its own job. Besides isolating failures, this # makes a producer job directly copyable into a downstream repository. # Native analyzers are the sole shared prerequisite and are built once here. diff --git a/gems/gigasail/tools/change_coupling.rb b/gems/gigasail/tools/change_coupling.rb index 5529faa81..36282cd65 100644 --- a/gems/gigasail/tools/change_coupling.rb +++ b/gems/gigasail/tools/change_coupling.rb @@ -1,5 +1,19 @@ # frozen_string_literal: true +# WIP anti-pattern experiment. Not run in CI: the value of its findings was +# never established, and the job that ran it existed for this tool alone. +# +# If the findings do prove worth acting on, this belongs in SlopCop::Bugspots +# rather than here. Bugspots already shells the same `git log --no-merges +# --name-only` and already accumulates co-change partners per file; this is a +# second scorer over the same extracted events, differing only in scope (all +# commits vs fix commits), weighting (support/confidence vs time decay), and +# the cross-module pair filter. Merging would drop one full-history scan and +# would let Bugspots reuse the rename-alias map below, which it lacks. It does +# NOT belong in SlopCop::Constraints: that registry is language-keyed and its +# findings are single-site and evidence-gated, while this is language-agnostic +# and its unit is a pair of files with no line and no evidence requirement. +# # Cross-module change coupling, from git history or (with --db) Lineage's # own rename-stable logical-unit ledger. # From 32dd6e7e9f6ae36130c73c1e2e328b059ebcede3 Mon Sep 17 00:00:00 2001 From: Brian Yahn Date: Sat, 1 Aug 2026 10:27:35 +0000 Subject: [PATCH 2/3] Build only the giga binary, not the whole gigasail workspace Two jobs built gems/gigasail with --workspace but install only `giga`. That also builds giga-ui, the axum web UI and LSP server, which `giga` never links: 47 crates exclusive to it (axum, hyper, tower-lsp, askama, rust-embed, rayon and their trees) out of the 212 it needs. giga-ui's binary is referenced nowhere in this workflow. Measured by cleaning exactly those 47 packages and rebuilding, pinned to two cores to match the runner: 3m52s of compilation, 442s of CPU, 222 MB of artifacts. That is the saving in each of the two jobs. cargo llvm-cov for Gigasail keeps --workspace: it measures that workspace's own coverage, so giga-ui belongs in it. Co-authored-by: Codex --- .github/workflows/ci.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81c1c1d4b..bc7c46428 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -182,7 +182,11 @@ jobs: # The ingestion round-trip test below skips silently (not fails) # when this binary is absent, so without this step CI could report # green while that contract was never actually exercised. - run: cargo build --release --manifest-path gems/gigasail/Cargo.toml --workspace + # + # --bin giga, not --workspace: the test resolves + # gems/gigasail/target/release/giga and nothing here wants giga-ui, + # whose axum/tower-lsp/askama stack is 47 crates giga never links. + run: cargo build --release --manifest-path gems/gigasail/Cargo.toml --bin giga - name: Verify runner adapters, dynamic planning, and canonical checkpoints run: bundle exec ruby -I gems/test-miser/test gems/test-miser/test/test_miser_test.rb - name: Verify PR step summary tallies @@ -1656,7 +1660,7 @@ jobs: cargo build --release --manifest-path gems/decomplex/Cargo.toml cargo build --release --manifest-path gems/sql-cov/Cargo.toml cargo build --release --manifest-path gems/nil-kill/Cargo.toml - cargo build --release --manifest-path gems/gigasail/Cargo.toml --workspace + cargo build --release --manifest-path gems/gigasail/Cargo.toml --bin giga mkdir -p tmp/sarif-binaries install -m 755 gems/fact-mine/target/release/fact-mine-rust tmp/sarif-binaries/fact-mine-rust install -m 755 gems/decomplex/target/release/decomplex-rust tmp/sarif-binaries/decomplex-rust From f41fdef417cdcbee51913c2476ee4f7b3a7e263f Mon Sep 17 00:00:00 2001 From: Brian Yahn Date: Sat, 1 Aug 2026 10:34:34 +0000 Subject: [PATCH 3/3] Consume the shared Rust binaries in nil-kill and test-miser Both jobs compiled crates that `sarif-rust-binaries` had already built: nil-kill rebuilt fact-mine and nil-kill, test-miser rebuilt gigasail. Three jobs, one set of binaries. They now download the artifact and install it to the target/release paths their tests resolve, the same way ruby-gems-coverage and fact-mine-rust-coverage already do. No cargo build remains outside the shared job. Waiting on that job is close to free in run time. Measured on run 30694977695: sarif-rust-binaries took 14m06s and is the critical path already - it gates seven jobs and the whole run was 19m - while these two took 4m59s and 6m48s and have no dependents at all. Dropping giga-ui brings the shared job to roughly 10m, after which nil-kill finishes near 12m and test-miser near 15m, both inside the window the shared job's dependents already occupy. Neither job compiles Rust any more, so the rust-toolchain step goes with it; the cargo references left in their suites are mocked (Open3 stubbed to raise ENOENT) or fixture argv, not real invocations. Co-authored-by: Codex --- .github/workflows/ci.yml | 41 ++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc7c46428..e4daca991 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -117,8 +117,8 @@ jobs: nil-kill-unit: name: nil-kill gem specs - needs: changes - if: ${{ needs.changes.outputs.run_gems == 'true' }} + needs: [changes, sarif-rust-binaries] + if: ${{ needs.changes.outputs.run_gems == 'true' && needs.sarif-rust-binaries.result == 'success' }} runs-on: ubuntu-latest env: COVERAGE: "0" @@ -137,11 +137,20 @@ jobs: node-version: 20 - name: Install Tree-sitter grammars run: npm install --legacy-peer-deps - - uses: dtolnay/rust-toolchain@stable - - name: Build Rust binaries + - uses: actions/download-artifact@v4 + with: + name: sarif-rust-binaries + path: tmp/sarif-binaries + # Built once by `sarif-rust-binaries` and copied to the target/release + # paths the specs resolve, rather than compiling the same two crates + # again on this runner. Waiting on that job costs nothing in run time: + # it is already the critical path (it gates seven other jobs), and this + # job finishes well inside the window its dependents occupy. + - name: Install shared Rust binaries run: | - cargo build --release --manifest-path gems/fact-mine/Cargo.toml - cargo build --release --manifest-path gems/nil-kill/Cargo.toml + chmod +x tmp/sarif-binaries/* + install -Dm755 tmp/sarif-binaries/fact-mine-rust gems/fact-mine/target/release/fact-mine-rust + install -Dm755 tmp/sarif-binaries/nil-kill-infer-rust gems/nil-kill/target/release/nil-kill-infer-rust # The collector IS this extension -- a collect loads it and no nil-kill # Ruby at all -- so without it every spec that runs one fails to require # it, and the specs guarded on its presence quietly test nothing. @@ -157,8 +166,8 @@ jobs: test-miser-checkpoint: name: Test Miser corpus and runner integration - needs: changes - if: ${{ needs.changes.outputs.run_gems == 'true' }} + needs: [changes, sarif-rust-binaries] + if: ${{ needs.changes.outputs.run_gems == 'true' && needs.sarif-rust-binaries.result == 'success' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -177,16 +186,20 @@ jobs: java-version: "17" - name: Install Jest oracle fixture runtime run: npm install --no-save --no-package-lock jest@30.0.5 - - uses: dtolnay/rust-toolchain@stable - - name: Build Gigasail release binary + - uses: actions/download-artifact@v4 + with: + name: sarif-rust-binaries + path: tmp/sarif-binaries + - name: Install shared Gigasail binary # The ingestion round-trip test below skips silently (not fails) # when this binary is absent, so without this step CI could report # green while that contract was never actually exercised. # - # --bin giga, not --workspace: the test resolves - # gems/gigasail/target/release/giga and nothing here wants giga-ui, - # whose axum/tower-lsp/askama stack is 47 crates giga never links. - run: cargo build --release --manifest-path gems/gigasail/Cargo.toml --bin giga + # Built once by `sarif-rust-binaries` rather than compiling gigasail + # again here. + run: | + chmod +x tmp/sarif-binaries/giga + install -Dm755 tmp/sarif-binaries/giga gems/gigasail/target/release/giga - name: Verify runner adapters, dynamic planning, and canonical checkpoints run: bundle exec ruby -I gems/test-miser/test gems/test-miser/test/test_miser_test.rb - name: Verify PR step summary tallies