Files
Dario Gabriel LipicarandClaude Opus 5 3694e85770 fix(ci): run the symbol gate, and fix what it does on Windows
The gate was exposed in `checks` and built by NOTHING. ci.yml names `tests`
specifically, `nix flake check` runs nowhere in this repo, and `ws test` builds
exactly one check per repo -- so the control that mechanically enforces the
one-runtime invariant was dead code here, exactly as it was in logos-basecamp.
The negative control is wired alongside it, always: a gate that has never been
seen to fail is indistinguishable from a broken one.

Three defects in the gate itself, all Windows-only, all inherited from the
logos-basecamp sibling this file was copied from and all found by cross-building
it there:

  * the peer sweep globbed lib/*.{dylib,so}. On Windows every liblogos_* shared
    image is staged into bin/ as a .dll, because the PE loader searches the
    executable's directory -- so it found ZERO owners and the exactly-one
    assertion could not pass on a correct tree.

  * `nm` and `c++filt` were called by their bare names. The cross bintools
    installs ONLY x86_64-w64-mingw32-prefixed ones, so neither was on PATH and
    every measurement read nothing; valid() then refused to assert over it.
    Fail-closed, but the gate could never run. Fixed with targetPrefix, which is
    "" natively and therefore a no-op here.

  * `nm --defined-only` counts PE import THUNKS as definitions: ld synthesizes a
    .text stub AND an __imp_<mangled> IAT slot per imported function. That
    reported images as definers of types they merely import. The paired __imp_
    entry is the discriminator, and it is the right one rather than merely a
    working one -- a genuine second copy statically linked in has no __imp_ slot
    and still counts. (The PE export table also hides the phantom, but it hides
    a real private copy too, trading a false positive for a false NEGATIVE.)

NOT covered: x86_64-windows, which is where a duplicate actually bites. `checks`
is native-only in this flake and Windows artifacts are built in release.yml, so
exposing the gate for that target is a follow-up. The gate itself is now correct
for PE -- verified in logos-basecamp, which does cross-build it.

Verified on aarch64-darwin: SYMBOL GATE PASS (TokenManager 1 definer
liblogos_protocol(35), LogosAPI 1 definer liblogos_qt_host(26), LogosAPIClient 1
definer liblogos_protocol(49); consumers 0) and NEGATIVE CONTROL PASS, rejecting
a planted duplicate at 49 symbols.

Also drops two dangling references to cmake/LogosSharedFromDll.cmake, the
single-provider shim deleted once the runtime became real shared libraries, and
the claim that liblogos_core is the provider -- it is not, which is precisely
why the assertion is exactly-one rather than naming an owner.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 19:56:47 -03:00

63 lines
2.4 KiB
YAML

name: CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
test:
# ATTIC_TOKEN_PUBLIC only exists in the public-cache environment; master
# jobs must opt into it to publish to the public cache.
environment: ${{ github.ref == 'refs/heads/master' && 'public-cache' || '' }}
strategy:
matrix:
include:
- arch: x86_64-linux
runner: ubuntu-latest
- arch: aarch64-linux
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Nix and set up cache
uses: logos-co/setup-nix-cache-action@v1
with:
attic-token-ci: ${{ secrets.ATTIC_TOKEN_CI }}
attic-token-public: ${{ secrets.ATTIC_TOKEN_PUBLIC }}
extra-nix-config: |
experimental-features = nix-command flakes
- name: Build
run: nix build --print-build-logs
- name: Run tests
run: nix build '.#checks.${{ matrix.arch }}.tests' --print-build-logs
# The one control that mechanically enforces the one-runtime invariant.
# Until this step existed the gate was exposed in `checks` and built by
# NOTHING: this workflow names `tests` specifically, `nix flake check` runs
# nowhere, and `ws test` builds exactly one check per repo. An absence
# assertion nobody runs is not an assertion.
#
# The negative control ships with it, always. It plants a REAL duplicate
# definer where an in-process consumer goes and asserts the gate REJECTS
# that tree; without it, a gate that has never been seen to fail is
# indistinguishable from a broken one.
#
# NOT covered here: x86_64-windows, which is where a duplicate actually
# bites -- PE has no symbol interposition, so the duplicate that Linux and
# macOS collapse to one is fatal only there. `checks` is native-only in this
# flake (forAllSystems at the top), and Windows artifacts are built in
# release.yml, so exposing the gate for that target is a follow-up rather
# than a line here. The gate ITSELF now handles the PE layout correctly --
# verified in logos-basecamp, which does cross-build it.
- name: One-runtime symbol gate
run: |
nix build '.#checks.${{ matrix.arch }}.symbol-gate' --print-build-logs
nix build '.#checks.${{ matrix.arch }}.symbol-gate-negative' --print-build-logs