byggsteg-4ad0d9be-65a1

job failed

time taken
9 seconds
started at
Wed Oct 14 17:43:31 2026
updated at
Wed Oct 14 17:43:40 2026
log uuid
4ad0d9be-65a1-488c-9e29-597a4f2d13c7
inspect the job's lambda expression
(lambda()
  `((task . ("maak-test" "byggsteg-version" "maak-deploy"))
    (daemon-name . "byggsteg-daemon")
    (project . "byggsteg")
    (branch-name . "trunk")
    (clone-url . "https://codeberg.org/jjba23/byggsteg.git")))
starting new job...


→ running command: cd "/etc/byggsteg/job-clone//byggsteg/trunk" && git reset --hard && git pull

HEAD is now at 2bda17e feat: ANSI support
From https://codeberg.org/jjba23/byggsteg
   2bda17e..7e3b12b  trunk      -> origin/trunk
Updating 2bda17e..7e3b12b
Fast-forward
 README.org                               |   2 +
 app/views/logs.scm                       |  35 ++++---
 lib/byggsteg/ansi.scm                    |  15 ++-
 lib/byggsteg/faces.scm                   |  59 ++++++++++++
 lib/byggsteg/job/steps.scm               | 122 +++++++++++++++++++++--
 maak.scm                                 |  20 +++-
 pub/js/byggsteg-log.js                   |   9 +-
 test/veritas/unit/ansi-spec.scm          |   6 +-
 test/veritas/unit/job-pipelines-spec.scm | 160 +++++++++++++++++++++++++++++++
 9 files changed, 397 insertions(+), 31 deletions(-)

→ running command: cd /etc/byggsteg/job-clone/byggsteg/trunk && uname -a

Linux wolk-jjba 7.1.5-gnu #1 SMP PREEMPT_DYNAMIC 1 x86_64 GNU/Linux

→ running command: cd /etc/byggsteg/job-clone/byggsteg/trunk && git log --name-status HEAD^..HEAD

commit 7e3b12b1c7486282a1f7f699c89031e8859677e5
Author: Josep Bigorra <jjbigorra@gmail.com>
Date:   Wed Oct 14 17:43:18 2026 +0200

    feat: ANSI support

M       README.org
M       app/views/logs.scm
M       lib/byggsteg/ansi.scm
M       lib/byggsteg/faces.scm
M       lib/byggsteg/job/steps.scm
M       maak.scm
M       pub/js/byggsteg-log.js
M       test/veritas/unit/ansi-spec.scm
M       test/veritas/unit/job-pipelines-spec.scm

→ running command: cd /etc/byggsteg/job-clone/byggsteg/trunk && maak test


scanning directories for unit tests...
scanning present working directory for unit tests...

shuffled the files with seed 985905980 (replay with VERITAS_SEED=985905980)

found unit tests: (log-streaming-spec.scm job-pipeline-spec.scm password-reset-spec.scm retry-spec.scm artifact-spec.scm job-pipelines-spec.scm console-resources-spec.scm deployment-identity-spec.scm about-page-spec.scm user-bootstrap-spec.scm job-search-spec.scm password-strength-spec.scm heatmap-spec.scm form-width-spec.scm terminal-glass-spec.scm error-pages-spec.scm retention-spec.scm ansi-spec.scm)


running unit tests from file: log-streaming-spec.scm, entrypoint: spec


������ info - shuffled with seed 985905980 (replay with VERITAS_SEED=985905980)
+----------------------------------------------+
[���� suite] job log streaming
  [���� test] output reaches the log a batch at a time, whole
    [������ assert] the line that completes the batch is the one that writes
    ��� got: ((calls-before-the-batch-completes 0) (text-held one
two
) (written-by-the-batch (one
two
three
)) (written-at-the-end (one
two
three
)) (calls-at-the-end 1))
  [���� test] a buffer writes only when it has something new to say
    [������ assert] nothing gathered, and nothing gathered again, are not writes
    ��� got: ((calls-of-an-empty-buffer 0) (first-flush (one
)) (calls-after-two-flushes 1))
  [���� test] a command is announced the way a finished log announces it
    [������ assert] the banner names the command and starts its own line
    ��� got: ((names-the-command #t) (starts-its-own-line #t))
  [���� test] a running job's log row is refreshed while it runs
    [������ assert] two lines are held, and the batch that completes three is written
    ��� got: ((before-the-batch ) (the-batch-is-in-the-row #t) (the-whole-log-is-in-the-row #t) (the-end-is-in-the-row #t))
  [���� test] one job's log is the log that is written
    [������ assert] streaming into a job writes its log and no other
    ��� got: ((the-job-log-is-written #t) (the-other-log-is-untouched ))
������ info - ran 1 tasks in: 0 seconds, 18318 microseconds

running unit tests from file: job-pipeline-spec.scm, entrypoint: spec


������ info - shuffled with seed 985905980 (replay with VERITAS_SEED=985905980)
+----------------------------------------------+
[���� suite] job pipeline
  [���� test] job data that is not a thunk is refused, not applied
    [������ assert] job data that is not a procedure raises
    ��� raised an error as expected
    [������ assert] a refused job is left for the sweep to fail
    ��� got: ()
  [���� test] the sweep fails what it cannot run, and runs a job with no log
  could not run job spec-unparseable: read-error (#f "#<unknown port>:1:21: unexpected end of input while searching for: ~A" (#\)) #f)

  could not run job spec-empty-job-data: misc-error (#f "byggsteg: job data did not evaluate to a procedure ~S" ("spec-empty-job-data") #f)

  could not run job spec-queued-not-a-thunk: misc-error (#f "byggsteg: job data did not evaluate to a procedure ~S" ("spec-queued-not-a-thunk") #f)

succeeded?: #t

succeeded?: #t

    [������ assert] every job ended as it should, and the logs are right
    ��� got: ()
������ info - ran 1 tasks in: 3 seconds, 66613 microseconds

running unit tests from file: password-reset-spec.scm, entrypoint: spec


������ info - shuffled with seed 985905980 (replay with VERITAS_SEED=985905980)
+----------------------------------------------+
[���� suite] a password-reset link
  [���� test] a link is worth following for the week after it was made
    [������ assert] yesterday is usable, the last instant of the week is usable, the instant after is not
    ��� got: ((made-a-minute-ago #t) (made-yesterday #t) (made-inside-the-week #t) (made-exactly-a-week-ago #f) (made-a-week-and-a-day-ago #f))
  [���� test] a link this deployment cannot date is not followed
    [������ assert] no row, no date and a date that is not a number all answer the same as an old link
    ��� got: ((no-such-token #f) (a-row-without-a-date #f) (a-row-whose-date-is-not-an-instant #f))
������ info - ran 1 tasks in: 0 seconds, 1009 microseconds

running unit tests from file: retry-spec.scm, entrypoint: spec


������ info - shuffled with seed 985905980 (replay with VERITAS_SEED=985905980)
+----------------------------------------------+
[���� suite] where a retry is offered
  [���� test] a list offers a retry only for a job that failed
    [������ assert] a green or a running row has nothing to retry; the red one does
    ��� got: ((failed . #t) (succeeded . #f) (running . #f) (queued . #f))
    [������ assert] and the row the rule answers for is the row that carries the button
    ��� got: ((failed . #t) (succeeded . #f) (running . #f) (queued . #f))
  [���� test] a job's own page offers a retry whatever its status
    [������ assert] every job but one still running can be run again from its page
    ��� got: ((failed . #t) (succeeded . #t) (running . #f) (queued . #t))
  [���� test] a reader who may not submit a retry is offered none
    [������ assert] with no permission at all, neither a row nor a job's own page offers a retry
    ��� got: ((failed . #f) (succeeded . #f) (running . #f) (queued . #f))
    [������ assert] and the page is no more generous than the list: a form a reader cannot send is not drawn
    ��� got: ((failed . #f) (succeeded . #f) (running . #f) (queued . #f))
    [������ assert] holding byggsteg:job-create, the rules read exactly as they do for a super user
    ��� got: ((failed . #t) (succeeded . #f) (running . #f) (queued . #f))
    [������ assert] and the row that rule answers for is the row that carries the form, for a reader who may send it
    ��� got: ((failed . #t) (succeeded . #f) (running . #f) (queued . #f))
    [������ assert] while a reader who may not send one is drawn no form, however red the row
    ��� got: ((failed . #f) (succeeded . #f) (running . #f) (queued . #f))
������ info - ran 1 tasks in: 0 seconds, 15825 microseconds

running unit tests from file: artifact-spec.scm, entrypoint: spec


������ info - shuffled with seed 985905980 (replay with VERITAS_SEED=985905980)
+----------------------------------------------+
[���� suite] artifacts
  [���� test] the table a collection writes to is the table the migrations make
    [������ assert] the artifact migration adds the artifact table
    ��� got: (id job_id title artifact_path artifact_size created_at updated_at)
  [���� test] a collected tarball is recorded, and the job it was built by finds it
    [������ assert] an artifact is read back by its id
    ��� got: #t
    [������ assert] the artifact keeps the job that collected it
    ��� got: spec-artifact-job
    [������ assert] the artifact keeps the size it was written with
    ��� got: 2048
    [������ assert] both collections of one job are its artifacts
    ��� got: (((id . spec-artifact-1) (job-id . spec-artifact-job) (title . byggsteg-job.tar.gz) (artifact-path . /tmp/byggsteg-artifact-spec-19629/spec-artifact-job.tar.gz) (artifact-size . 2048) (created-at . 1791992618) (updated-at . #f)) ((id . spec-artifact-2) (job-id . spec-artifact-job) (title . byggsteg-job-2.tar.gz) (artifact-path . /tmp/byggsteg-artifact-spec-19629/spec-artifact-job-2.tar.gz) (artifact-size . 4096) (created-at . 1791992618) (updated-at . #f)))
    [������ assert] a job nothing was collected for draws no artifacts
    ��� got: ()
  [���� test] only a file inside the artifact directory may be downloaded
    [������ assert] no row outside the artifact directory is servable
    ��� got: ()
    [������ assert] a recorded tarball inside it is servable
    ��� got: #t
    [������ assert] a row with no path is not servable
    ��� got: #f
  [���� test] a job asks for one tarball of bare paths, or a bundle per name
    [������ assert] a list of paths is one unnamed bundle, in the order written
    ��� got: ((#f dist/wikimusic-api docs/manual))
    [������ assert] each named bundle keeps its name and its paths
    ��� got: ((binaries dist bin) (docs docs/manual))
    [������ assert] bare paths and bundles mix, and keep the order they were written in
    ��� got: ((#f README.org) (binaries dist) (docs docs/manual))
    [������ assert] a bundle written as one list is a name and the paths behind it
    ��� got: ((binaries dist bin))
    [������ assert] a name written as a symbol is read as the name it spells
    ��� got: ((binaries dist))
    [������ assert] one path written without its list is still one path
    ��� got: ((#f dist/app))
    [������ assert] a field of nothing asks for nothing
    ��� got: ()
    [������ assert] a bundle that names no path is dropped rather than packed empty
    ��� got: ()
  [���� test] forgetting a job's artifacts takes the tarballs and the rows
    [������ assert] both go, and a row naming a file outside the directory leaves it alone
    ��� got: ((forgotten 3) (rows-left 0) (tarballs-gone (#f #f)) (a-file-outside-the-directory-was-left-alone #t))
  [���� test] a sweep removes the tarballs no row points at, and nothing else
    [������ assert] the old orphan goes; the fresh one, the named one, a name byggsteg never writes and a directory stay
    ��� got: ((removed (/tmp/byggsteg-artifact-spec-19629/orphan-old.tar.gz)) (the-old-orphan-is-gone #f) (the-fresh-one-is-kept #t) (one-a-row-still-names-is-kept #t) (a-name-byggsteg-never-writes-is-left #t) (a-directory-is-left #t))
  [���� test] the worker's sweep runs on its interval, not on every visit
    [������ assert] a due visit removes, the one straight after it does not look
    ��� got: ((a-due-visit-removed 1) (a-visit-straight-after-it-removed 0) (the-orphan-it-did-not-look-for-is-still-there #t))
  [���� test] a download is offered under a name a header can carry
    [������ assert] a title becomes a plain file name
    ��� got: my-build--trunk-..-x.tar.gz
    [������ assert] the second tarball of one job is numbered
    ��� got: byggsteg-job-2.tar.gz
    [������ assert] a named bundle is offered under its own name
    ��� got: (binaries.tar.gz binaries-2.tar.gz docs-manual.tar.gz)
    [������ assert] a size is read in the unit a reader can hold in mind
    ��� got: 2.0 KiB
������ info - ran 1 tasks in: 0 seconds, 2572 microseconds

running unit tests from file: job-pipelines-spec.scm, entrypoint: spec


������ info - shuffled with seed 985905980 (replay with VERITAS_SEED=985905980);;; note: source file ./lib/byggsteg/job/steps.scm
;;;       newer than compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/byggsteg/trunk/lib/byggsteg/job/steps.scm.go
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;;       or pass the --no-auto-compile argument to disable.
;;; compiling ./lib/byggsteg/job/steps.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/byggsteg/trunk/lib/byggsteg/job/steps.scm.go
;;; note: source file ./lib/byggsteg/faces.scm
;;;       newer than compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/byggsteg/trunk/lib/byggsteg/faces.scm.go
;;; compiling ./lib/byggsteg/faces.scm
;;; note: source file ./lib/byggsteg/ansi.scm
;;;       newer than compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/byggsteg/trunk/lib/byggsteg/ansi.scm.go
;;; compiling ./lib/byggsteg/ansi.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/byggsteg/trunk/lib/byggsteg/ansi.scm.go
WARNING: (hygguile hygguile): imported module (hygguile components select) overrides core binding `select'
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/byggsteg/trunk/lib/byggsteg/faces.scm.go
;;; note: source file ./test/veritas/unit/job-pipelines-spec.scm
;;;       newer than compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/byggsteg/trunk/test/veritas/unit/job-pipelines-spec.scm.go
;;; compiling ./test/veritas/unit/job-pipelines-spec.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/byggsteg/trunk/test/veritas/unit/job-pipelines-spec.scm.go

+----------------------------------------------+
[���� suite] job pipelines
  [���� test] the jobs a request asks for are read from its data
    [������ assert] a list of jobs and a single job are read alike
    ��� got: ((a-list-of-two 2) (a-list-of-one 1) (the-first-project-names-the-job byggsteg) (a-pipeline-of-unnamed-jobs pipeline) (a-pipeline-of-bare-commands trivial))
  [���� test] every job of a pipeline is run, in the order it is written
succeeded?: #t

    [������ assert] both stages ran, the first before the second
    ��� got: ((the-first-job-ran #t) (the-second-job-ran #t) (in-the-order-they-are-written #t) (outcome (1 0 0)))
  [���� test] a job that fails stops the pipeline
succeeded?: #f

    [������ assert] the job after the failure did not run, and the pipeline failed
    ��� got: ((the-later-job-ran #f) (outcome (0 0 1)))
  [���� test] a task that fails stops the tasks behind it in the same job
succeeded?: #f

    [������ assert] the task behind the failure did not run, and the job failed
    ��� got: ((the-failing-task-ran #t) (the-task-behind-it-ran #f) (outcome (0 0 1)))
  [���� test] a command's output outside ASCII reaches the log it wrote
succeeded?: #t

    [������ assert] the accented word, the block and the Japanese word are all there
    ��� got: ((the-line-is-what-the-command-printed #t) (a-replacement-character #f) (outcome (1 0 0)))
  [���� test] a job's commands read text in a locale of their own
succeeded?: #t

succeeded?: #t

    [������ assert] a command with no locale counts characters, and one a job named counts bytes
    ��� got: ((the-characters-of-a-word #t) (the-bytes-of-it #f) (a-locale-the-job-names-itself #t) (outcome (1 0 0)))
    [������ assert] a locale a deployment names, or an empty naming, is read as it is
    ��� fail - error, expect: ((a-deployment-that-names-none #t) (a-deployment-that-names-its-own (LANG=de_DE.UTF-8)) (an-empty-naming #t) (and-the-request-that-named-none (PATH=/usr/bin LC_ALL=C.UTF-8))), got: ((a-deployment-that-names-none #t) (a-deployment-that-names-its-own LANG=de_DE.UTF-8) (an-empty-naming #t) (and-the-request-that-named-none PATH=/usr/bin LC_ALL=C.UTF-8))
  [���� test] every task of a job is run, and each is a step of its own
succeeded?: #t

    [������ assert] a job that asks for two tasks ran two, and the job passed
    ��� got: ((how-many-tasks-ran 2) (outcome (1 0 0)))
  [���� test] a pipeline of one job is a job
succeeded?: #t

    [������ assert] a single job's commands ran and its row says so
    ��� got: ((the-job-ran #t) (outcome (1 0 0)))
  [���� test] a stage that names several bundles collects a tarball for each
succeeded?: #t

    [������ assert] the bare path's tarball keeps the title, and each bundle its name
    ��� got: ((how-many 3) (named-as-asked (spec-spec-collecting.tar.gz binaries-2.tar.gz docs-3.tar.gz)) (the-tarballs-are-there (#t #t #t)) (outcome (1 0 0)))
������ info - ran 1 tasks in: 1 seconds, -657251 microseconds

��� error - 
aborting due to error in test case...

;;; note: source file /etc/byggsteg/job-clone/byggsteg/trunk/maak.scm
;;;       newer than compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/byggsteg/trunk/maak.scm.go
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;;       or pass the --no-auto-compile argument to disable.
;;; compiling /etc/byggsteg/job-clone/byggsteg/trunk/maak.scm
;;; /etc/byggsteg/job-clone/byggsteg/trunk/maak.scm:377:0: warning: shadows previous definition of `i18n-init-es' at /etc/byggsteg/job-clone/byggsteg/trunk/maak.scm:373:0
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/byggsteg/trunk/maak.scm.go
Backtrace:
In ice-9/boot-9.scm:
  1784:12  7 (with-exception-handler _ _ #:unwind? _ #:unwind-for-type _)
In unknown file:
           6 (apply-smob/0 #<thunk 7f18f5674340>)
In ice-9/boot-9.scm:
    733:2  5 (call-with-prompt _ _ #<procedure default-prompt-handler (k proc)>)
In ice-9/eval.scm:
    619:8  4 (_ #(#(#<directory (guile-user) 7f18f5677c80>)))
In ice-9/command-line.scm:
   187:19  3 (_ #<input: custom-port 7f18f565e3f0>)
In unknown file:
           2 (eval ((@ (maak main) main)) #<directory (guile-user) 7f18f5677c80>)
In srfi/srfi-1.scm:
    750:9  1 (for-each #<procedure 7f18f4759198 at maak/maak.scm:87:12 (task)> (test))
In maak/dsl.scm:
    89:12  0 ($ _ #:verbose? _ #:join _)

maak/dsl.scm:89:12: In procedure $:

Non-zero exit code when running!
Command: guix time-machine --channels=channels.scm -- shell -m manifest.scm -- guile -L ./lib -L . -L ./test -c '(begin (setlocale LC_ALL "C.UTF-8") (use-modules (veritas runner)) (run-tests))'
Exit code: 1



--------------------------------------------------------------

Maak: the infinitely extensible command runner

Loading tasks from Maak file: /etc/byggsteg/job-clone/byggsteg/trunk/maak.scm

Executing Maak tasks: test

--------------------------------------------------------------

=> Running Maak task: test

  Run the project's test suite.

The specs live under test/veritas/unit.  That is where the runner looks for
suites -- given the test root ./test, the module prefix `veritas' and the suite
name `unit' -- and it is also what their own `(veritas unit ...)' module names
resolve to on the load path below.

The run names the locale it reads in rather than inheriting one, and it names it
before the runner is asked for: Guile reads a page by the locale in force, and a
pattern over a page that holds a character outside ASCII reports matches where
there are none under a locale that names no encoding.  `C.UTF-8' is that name
for a machine that has never generated a locale -- a service, a container, and
this project's own continuous integration, where the job that tests byggsteg is
run by a byggsteg daemon whose Shepherd unit names no locale at all.  The suite
reads the pages of this console, whose prose, whose marks and whose console
output are not ASCII; run without a locale it would find elements no browser
knows and fail for a reason that has nothing to do with the change it was run to
judge.  Naming it here is part of what the pinned manifest is for: a run of the
suite reads the same pages wherever the pipeline runs.