Bump the version and fix the CI image

metacpan/metacpan-api, which the build ran in, switched to an
unprivileged user. apt-get cannot write /var/lib/apt/lists there and
gives up with "Permission denied", so cmake never got installed and the
collocatordb build died with "cmake: command not found". The image has no
sudo either, and a job cannot ask for another user, so this needs a
different image: the official perl one runs as root and brings cpanm,
pinned to its distribution so that an upstream rebuild cannot move
rocksdb underneath us.

Two things follow from the change. morbo comes from the local lib now
rather than from the image, so the server test needs perl5/bin on the
PATH, and the cache key carries the image, because perl5/ only holds what
cpanm found missing in the image it was built in.

A failed package installation is also reported where it happens now
instead of surfacing much later as a missing command.

Verified with gitlab-ci-local: all 12 tests pass, against the rocksdb 9.10
of trixie.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I4ed59866b57aa10e39c28390a9a9e2b7d74780e5
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index cfee89e..754e65d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,4 +1,8 @@
-image: metacpan/metacpan-api
+# The build needs root, for apt-get, and a perl with cpanm. metacpan/metacpan-api
+# used to provide both, but it runs as an unprivileged user now, where apt-get
+# fails with "Permission denied" and cmake never gets installed. Pinned to the
+# distribution as well, so that an upstream rebuild cannot move rocksdb under us.
+image: perl:5.40-trixie
 
 variables:
   # Set `CCACHE_BASEDIR` and `CCACHE_DIR` to point `ccache` towards the cached
@@ -20,8 +24,10 @@
 build-and-test:
   stage: build
   cache:
-    # Cache is shared between branches, but has a unique cache per job.
-    key: derekovecs
+    # Cache is shared between branches, but has a unique cache per job. The
+    # image is part of the key: perl5/ holds what cpanm decided was missing in
+    # that image, so a cache from another one is incomplete.
+    key: derekovecs-perl-5.40-trixie
     paths:
       # Note: directories should align with `$APT_CACHE_DIR` and `$CCACHE_DIR`.
       - apt-cache/
@@ -36,6 +42,9 @@
     - apt-get update && apt-get -o dir::cache::archives="$APT_CACHE_DIR" -y install ccache cmake librocksdb-dev libgflags-dev libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev libomp-dev
     # ccache only makes the build faster, it must never be able to make it fail,
     # so everything that uses it is guarded and CCACHE_OPTS stays empty without it
+    # a failed package install used to show up much later as "cmake: command
+    # not found" in the middle of the collocatordb build
+    - command -v cmake > /dev/null || { echo "cmake is missing, the package installation did not work"; exit 1; }
     - if CCACHE=$(command -v ccache); then ln -sf "$CCACHE" /usr/local/sbin/gcc && ln -sf "$CCACHE" /usr/local/sbin/g++ && CCACHE_OPTS="-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache"; else echo "ccache is not available - building without it"; CCACHE_OPTS=""; fi
     - end_section install_linux_packages
 
@@ -67,6 +76,8 @@
     - end_section build_derekovecs-server
 
     - start_section run_derekovecs-server "Testing DeReKoVecs server"
+    # the server test starts morbo, which cpanm installed into the local lib
+    - export PATH="$CI_PROJECT_DIR/perl5/bin:$PATH"
     - prove --verbose t
     - end_section run_derekovecs-server
 
diff --git a/Changelog.md b/Changelog.md
index 0657d12..4eb93ad 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,5 +1,18 @@
 # Changelog
 
+## [0.98] - 2026-08-21
+
+- the per request diagnostics of the vector code are off unless
+  `DEREKOVECS_DEBUG` is set. Every neighbourhood request wrote a few hundred
+  lines - one per window position, one per vocabulary lookup, the whole JSON of
+  a similar profile - which came to a million lines a day on
+  corpora.ids-mannheim.de and filled the log partition of the machine. Startup
+  and error messages are unaffected
+- the per request narration of the perl side - which word is being looked up,
+  which result comes from a cache, which static file was fetched - is logged at
+  debug level now. It repeated what the access log line of the same request
+  already says
+
 ## [0.97] - 2026-08-21
 
 - crawlers that collect training data for language models are answered with
@@ -14,16 +27,6 @@
 - `robots.txt` is served at every path, for installations that own their host
   name; behind a proxy that mounts derekovecs below a path, the site wide
   robots.txt still has to say it
-- the per request diagnostics of the vector code are off unless
-  `DEREKOVECS_DEBUG` is set. Every neighbourhood request wrote a few hundred
-  lines - one per window position, one per vocabulary lookup, the whole JSON of
-  a similar profile - which came to a million lines a day on
-  corpora.ids-mannheim.de and filled the log partition of the machine. Startup
-  and error messages are unaffected
-- the per request narration of the perl side - which word is being looked up,
-  which result comes from a cache, which static file was fetched - is logged at
-  debug level now. It repeated what the access log line of the same request
-  already says
 
 ## [0.96] - 2026-07-31
 
diff --git a/script/derekovecs-server b/script/derekovecs-server
index 9f5dbec..184bed0 100755
--- a/script/derekovecs-server
+++ b/script/derekovecs-server
@@ -1,6 +1,6 @@
 #!/usr/bin/env perl
 
-our $VERSION = '0.97';
+our $VERSION = '0.98';
 
 use IDS::DeReKoVecs::Read;
 use Mojolicious::Lite;