ci: run tree-sitter FFI gate on a container-safe nix runner #359

Merged
nsaspy merged 5 commits from ci/tree-sitter-runner-labels into main 2026-09-04 19:44:22 +00:00
Owner

Runtime invariant

The tree-sitter CI gate must run the real FFI build and the full native
test suite in the environment the runtime is actually built against (the
pinned nixpkgs flake), not a divergent apt environment. Runner jobs on
this Forgejo instance execute in Docker containers without systemd, so
Nix is installed with --init none and the daemon is spawned directly.

Diagnosis (infra vs job code)

The failures were job code, not runner infrastructure:

  • Run 224 (and every PR run since the #97 merge) failed at the apt step:
    tree-sitter-python-src and tree-sitter-javascript-src do not exist
    on ubuntu-24.04 (reproduced locally in a stock ubuntu:24.04 container:
    apt exit 100).
  • The same workflow succeeded on push runs that predated the #97 merge
    (runs 77/86), and ci.yml/pack-install.yml stayed green on the same
    runner fleet throughout - the fleet and labels were never the problem.
  • PR runs failed because pull_request jobs execute the merge ref: main
    already carried the broken package list, so every PR merge ref
    inherited it. After #349 merged, push runs on main fail as well.

Changes

  • .github/workflows/tree-sitter.yml: replace the apt lane with
    nix develop (container-safe Nix install: --init none + direct
    daemon spawn, then FFI build, grammar fixture links, full suite,
    whitespace check).
  • flake.nix: add pkg-config to the devShell (without it the Makefile
    silently produced a foreign library with undefined tree-sitter
    symbols); add an incompatible-abi grammar fixture derivation (the
    nix lane never built it, failing two tests); pin
    LANG/LC_ALL=C.UTF-8 (locale-less containers mis-decoded non-ASCII
    test literals, failing two more tests).
  • test/rlm_project_query_test.pl: fix
    read_only_project_root_is_a_structured_failure - it never registered
    a grammar (could only fail with source_parse_failed, never the
    expected kb_unwritable) and its chmod lockout does not apply to the
    root user CI runs as; the KB root is now blocked by a regular file,
    deterministic in any environment.

Non-goals

  • Does not fix nix.yml itself (same container/systemd installer root
    cause; follow-up slice).
  • Does not touch the paid-openrouter gate failure (missing explicit paid
    model configuration on this instance).
  • Does not change runtime Prolog code.

Verification evidence

  • Exact job steps pass end-to-end in a systemd-less ubuntu:24.04
    container with a fresh Nix install: 65/65 tree-sitter suite tests
    green (machine-recorded in .prolog/facts.kb).
  • Deterministic baseline: test/run_tests.pl 1179/1179,
    test/check_runtime.pl, test/load_all.pl, git diff --check all
    green.
  • prolog-verify gate passed at the pushed HEAD content state.

Follow-up

  • Apply the same container-safe Nix install pattern to nix.yml.
  • Configure the paid OpenRouter model secret or mark the paid gate as
    instance-gated.
## Runtime invariant The tree-sitter CI gate must run the real FFI build and the full native test suite in the environment the runtime is actually built against (the pinned nixpkgs flake), not a divergent apt environment. Runner jobs on this Forgejo instance execute in Docker containers without systemd, so Nix is installed with `--init none` and the daemon is spawned directly. ## Diagnosis (infra vs job code) The failures were **job code, not runner infrastructure**: - Run 224 (and every PR run since the #97 merge) failed at the apt step: `tree-sitter-python-src` and `tree-sitter-javascript-src` do not exist on ubuntu-24.04 (reproduced locally in a stock ubuntu:24.04 container: apt exit 100). - The same workflow succeeded on push runs that predated the #97 merge (runs 77/86), and `ci.yml`/`pack-install.yml` stayed green on the same runner fleet throughout - the fleet and labels were never the problem. - PR runs failed because pull_request jobs execute the merge ref: main already carried the broken package list, so every PR merge ref inherited it. After #349 merged, push runs on main fail as well. ## Changes - `.github/workflows/tree-sitter.yml`: replace the apt lane with `nix develop` (container-safe Nix install: `--init none` + direct daemon spawn, then FFI build, grammar fixture links, full suite, whitespace check). - `flake.nix`: add `pkg-config` to the devShell (without it the Makefile silently produced a foreign library with undefined tree-sitter symbols); add an `incompatible-abi` grammar fixture derivation (the nix lane never built it, failing two tests); pin `LANG/LC_ALL=C.UTF-8` (locale-less containers mis-decoded non-ASCII test literals, failing two more tests). - `test/rlm_project_query_test.pl`: fix `read_only_project_root_is_a_structured_failure` - it never registered a grammar (could only fail with `source_parse_failed`, never the expected `kb_unwritable`) and its chmod lockout does not apply to the root user CI runs as; the KB root is now blocked by a regular file, deterministic in any environment. ## Non-goals - Does not fix `nix.yml` itself (same container/systemd installer root cause; follow-up slice). - Does not touch the paid-openrouter gate failure (missing explicit paid model configuration on this instance). - Does not change runtime Prolog code. ## Verification evidence - Exact job steps pass end-to-end in a systemd-less ubuntu:24.04 container with a fresh Nix install: 65/65 tree-sitter suite tests green (machine-recorded in `.prolog/facts.kb`). - Deterministic baseline: `test/run_tests.pl` 1179/1179, `test/check_runtime.pl`, `test/load_all.pl`, `git diff --check` all green. - prolog-verify gate passed at the pushed HEAD content state. ## Follow-up - Apply the same container-safe Nix install pattern to `nix.yml`. - Configure the paid OpenRouter model secret or mark the paid gate as instance-gated.
ci: run tree-sitter FFI gate on a container-safe nix runner
Some checks failed
CI / REAL OpenRouter integration (pull_request) Has been skipped
Clean SWI pack install / Install and load copied pack (pull_request) Successful in 42s
CI / Deterministic unit and load checks (pull_request) Successful in 2m11s
Tree-sitter FFI / Direct SWI-Prolog Tree-sitter FFI (pull_request) Successful in 11m13s
Nix flake / Flake package and clean runtime load (pull_request) Failing after 5m36s
Paid OpenRouter / Pinned paid OpenRouter integration (pull_request) Failing after 34s
0d79941df8
The tree-sitter workflow failed on every pull_request since #97 landed:
its apt lane installs tree-sitter-python-src and tree-sitter-javascript-src,
which do not exist on ubuntu-24.04 (reproduced: apt exit 100). The same
broken package list also reached main via the #349 merge, so push runs
now fail too. Runner infrastructure is healthy - ci.yml and pack-install
lanes stayed green on the same fleet.

Replace the apt lane with the hermetic nix environment the flake already
provides:

- install Nix with --init none and spawn nix-daemon directly; Forgejo
  runner jobs execute in Docker containers without systemd, which is
  also what broke nix-installer-action in nix.yml
- add pkg-config to the devShell: without it the Makefile silently
  produced a foreign library with undefined tree-sitter symbols
- provide the incompatible-ABI grammar fixture as a flake derivation
  (the nix lane previously never built it, failing two tests)
- pin LANG/LC_ALL=C.UTF-8 in the devShell so test sources with
  non-ASCII literals are read as UTF-8 in the locale-less runner
  container (fixed utf8_ranges_are_byte_offsets and
  unicode_points_use_tree_sitter_byte_columns)
- fix read_only_project_root_is_a_structured_failure: it never
  registered a grammar, so it could only ever fail with
  source_parse_failed, and its chmod-based root lockout does not
  apply to the root user CI runs as; the KB root is now blocked by a
  regular file, which is deterministic in any environment

Evidence: the exact job steps pass in a systemd-less ubuntu:24.04
container (65/65 tests), the deterministic baseline suite passes
(1179 tests), static load and runtime checks pass, machine-recorded
in .prolog.
nsaspy force-pushed ci/tree-sitter-runner-labels from 0d79941df8
Some checks failed
CI / REAL OpenRouter integration (pull_request) Has been skipped
Clean SWI pack install / Install and load copied pack (pull_request) Successful in 42s
CI / Deterministic unit and load checks (pull_request) Successful in 2m11s
Tree-sitter FFI / Direct SWI-Prolog Tree-sitter FFI (pull_request) Successful in 11m13s
Nix flake / Flake package and clean runtime load (pull_request) Failing after 5m36s
Paid OpenRouter / Pinned paid OpenRouter integration (pull_request) Failing after 34s
to 8f0515da41
Some checks failed
CI / REAL OpenRouter integration (pull_request) Has been skipped
Clean SWI pack install / Install and load copied pack (pull_request) Successful in 1m40s
CI / Deterministic unit and load checks (pull_request) Failing after 2m24s
Nix flake / Flake package and clean runtime load (pull_request) Failing after 5m38s
Tree-sitter FFI / Direct SWI-Prolog Tree-sitter FFI (pull_request) Successful in 8m44s
Paid OpenRouter / Pinned paid OpenRouter integration (pull_request) Failing after 55s
2026-09-04 18:08:13 +00:00
Compare
- .prolog state resolved to the incoming #359 task evidence (repo convention)
- main-side changes (#335 adoption, #349/#350 streaming) carry no overlap with
  the tree-sitter CI lane, flake devShell, or project-query test fix
chore(verify): record PR 359 merge reconcile evidence at 23b9aff
Some checks failed
CI / REAL OpenRouter integration (pull_request) Has been skipped
Paid OpenRouter / Pinned paid OpenRouter integration (pull_request) Failing after 1m8s
Clean SWI pack install / Install and load copied pack (pull_request) Successful in 1m24s
Tree-sitter FFI / Direct SWI-Prolog Tree-sitter FFI (pull_request) Successful in 8m30s
Nix flake / Flake package and clean runtime load (pull_request) Failing after 5m35s
CI / Deterministic unit and load checks (pull_request) Has been cancelled
22a9a489a1
ci: re-trigger canonical gate after cancelled run 853
Some checks failed
CI / REAL OpenRouter integration (pull_request) Has been skipped
Paid OpenRouter / Pinned paid OpenRouter integration (pull_request) Failing after 53s
Clean SWI pack install / Install and load copied pack (pull_request) Successful in 1m6s
CI / Deterministic unit and load checks (pull_request) Successful in 2m24s
Nix flake / Flake package and clean runtime load (pull_request) Failing after 5m45s
Tree-sitter FFI / Direct SWI-Prolog Tree-sitter FFI (pull_request) Successful in 6m5s
e244020d5c
nsaspy merged commit 6092c2a9ba into main 2026-09-04 19:44:22 +00:00
Sign in to join this conversation.
No description provided.