starting new job...
→ running command: cd "/etc/byggsteg/job-clone//wikimusic/trunk" && git reset --hard && git pull
HEAD is now at 219e32c chore: Update guile-scriba
Already up to date.
→ running command: cd /etc/byggsteg/job-clone/wikimusic/trunk && uname -a
Linux wolk-jjba 7.2.11-gnu #1 SMP PREEMPT_DYNAMIC 1 x86_64 GNU/Linux
→ running command: cd /etc/byggsteg/job-clone/wikimusic/trunk && git log --name-status HEAD^..HEAD
commit 219e32c99558558820dfd68e514a6c00a9b7e411
Author: Josep Bigorra <jjbigorra@gmail.com>
Date: Mon Oct 26 13:24:37 2026 +0100
chore: Update guile-scriba
The pin moves to v0.4.5, a maintenance release: scriba's log-level suite called
(apply test ...), which Veritas cannot expand, so its test file stopped
compiling. Nothing in the library's API, behaviour or documentation changed,
so the shell this manifest describes is the same one with a test suite that
runs again.
🤖 Generated with [ECA](https://eca.dev) (deepseek/deepseek-flash)
Co-Authored-By: eca-agent <git@eca.dev>
M manifest.scm
→ running command: cd /etc/byggsteg/job-clone/wikimusic/trunk && maak test
scanning directories for unit tests...
scanning present working directory for unit tests...
shuffled the files with seed 384536129 (replay with VERITAS_SEED=384536129)
found unit tests: (views-spec.scm domain-spec.scm about-spec.scm controller-spec.scm assets-spec.scm error-pages-spec.scm auth-spec.scm guitarpro-view-spec.scm guitarpro-spec.scm config-spec.scm sql-spec.scm)
running unit tests from file: views-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 384536129 (replay with VERITAS_SEED=384536129)
+----------------------------------------------+
[📑 suite] The languages a page offers
[🧪 test] every offered language is one this instance ships
[⚙️ assert] the four catalogs are offered
✅ got: (en_US nl_NL es_ES ja_JP)
[🧪 test] each language is named in that language
[⚙️ assert] en_US is named
✅ got: #t
[⚙️ assert] nl_NL is named
✅ got: #t
[⚙️ assert] es_ES is named
✅ got: #t
[⚙️ assert] ja_JP is named
✅ got: #t
[🧪 test] a compiled catalog stands behind each offered language
[⚙️ assert] en_US has a catalog
✅ got: #t
[⚙️ assert] nl_NL has a catalog
✅ got: #t
[⚙️ assert] es_ES has a catalog
✅ got: #t
[⚙️ assert] ja_JP has a catalog
✅ got: #t
+----------------------------------------------+
[📑 suite] Where the shell reads its own files
[🧪 test] no file of the interface is somebody else's to serve
[⚙️ assert] no font host
✅ got: #f
[⚙️ assert] and none of the hosts a face was fetched from
✅ got: #f
[⚙️ assert] no icon CDN
✅ got: #f
[⚙️ assert] and no typeface read from somebody's static assets
✅ got: #f
[🧪 test] an instance that serves its own reads them off itself
[⚙️ assert] the stylesheet the page is laid out with
✅ got: #t
[⚙️ assert] and the icon the tab is marked with
✅ got: #t
[🧪 test] a deployment that serves them elsewhere moves every one of them
[⚙️ assert] the stylesheet
✅ got: #t
[⚙️ assert] the type the page is set in
✅ got: #t
[⚙️ assert] the glyphs its controls wear
✅ got: #t
[⚙️ assert] and the icon, with no address left behind
✅ got: #t
+----------------------------------------------+
[📑 suite] A page a browser can read
[🧪 test] no non-void element is closed as a self-closed tag
[⚙️ assert] each one is closed, not reopened
✅ got: #f
[🧪 test] the body the caller passed is the body that is served
[⚙️ assert] the content survives
✅ got: #t
[⚙️ assert] and it stands inside the document
✅ got: #t
+----------------------------------------------+
[📑 suite] A page a reader is reading
[🧪 test] the navigation is left to scroll away while reading
[⚙️ assert] the bar is still rendered
✅ got: #t
[⚙️ assert] nothing pins it
✅ got: #f
[⚙️ assert] no offset holds it there
✅ got: #f
[⚙️ assert] and it does not float above the text
✅ got: #f
[🧪 test] the navigation is pinned while browsing
[⚙️ assert] the bar keeps its place
✅ got: #t
[⚙️ assert] just below the top edge
✅ got: #t
[🧪 test] the whole template carries the reading mode down to the bar
[⚙️ assert] a reading page still has a bar
✅ got: #t
[⚙️ assert] but nothing pins it
✅ got: #f
[⚙️ assert] and every other page keeps it
✅ got: #t
+----------------------------------------------+
[📑 suite] The footer
[🧪 test] no class is asked for twice
[⚙️ assert] a clean class attribute
✅ got: #f
[🧪 test] it offers the way back to the top
[⚙️ assert] the control says what it does
✅ got: #t
[⚙️ assert] and it is the one that scrolls
✅ got: #t
[🧪 test] it states the version this instance runs
[⚙️ assert] the version is named
✅ got: #t
[🧪 test] it points at the code, the manual and the licence
[⚙️ assert] where the source is
✅ got: #t
[⚙️ assert] where the manual is
✅ got: #t
[⚙️ assert] and where the licence is written out
✅ got: #t
+----------------------------------------------+
[📑 suite] Choosing a language
[🧪 test] the control posts the choice to the preference route
[⚙️ assert] the form names the route
✅ got: #t
[⚙️ assert] the menu is the posted field
✅ got: #t
[🧪 test] every offered language is a row of the menu
[⚙️ assert] en_US is offered
✅ got: #t
[⚙️ assert] nl_NL is offered
✅ got: #t
[⚙️ assert] es_ES is offered
✅ got: #t
[⚙️ assert] ja_JP is offered
✅ got: #t
[🧪 test] the control names itself for a reader and for assistive tech
[⚙️ assert] the label is bound to the menu
✅ got: #t
[⚙️ assert] and says what it is
✅ got: #t
[🧪 test] the page states the language it is being read in
[⚙️ assert] the language being read is the row shown
✅ got: #t
[⚙️ assert] and a language not being read is not
✅ got: #f
ℹ️ info - ran 6 tasks in: 0 seconds, 293725 microseconds
running unit tests from file: domain-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 384536129 (replay with VERITAS_SEED=384536129)
+----------------------------------------------+
[📑 suite] Which related rows belong to an entry
[🧪 test] an artist is matched on the artist's identifier
[⚙️ assert] the row naming this artist
✅ got: (((artist-identifier . artist-1) (genre-identifier . genre-1) (song-identifier . song-1) (display-name . the one that matches)))
[🧪 test] a genre is matched on the genre's identifier
[⚙️ assert] the row naming this genre
✅ got: (((artist-identifier . artist-1) (genre-identifier . genre-1) (song-identifier . song-1) (display-name . the one that matches)))
[🧪 test] the identifier compared against is the entry's own
[⚙️ assert] a row naming a song is not the artist's row
✅ got: ()
[⚙️ assert] nor is another entry's row this one's
✅ got: ()
[🧪 test] a song is matched on the song's identifier
[⚙️ assert] the row naming this song
✅ got: (((artist-identifier . artist-1) (genre-identifier . genre-1) (song-identifier . song-1) (display-name . the one that matches)))
+----------------------------------------------+
[📑 suite] What a sort control means
[🧪 test] every sort the pages offer maps onto its own clause
[⚙️ assert] newest first
✅ got: ((created-at desc))
[⚙️ assert] oldest first
✅ got: ((created-at asc))
[⚙️ assert] edited most recently
✅ got: ((last-edited-at desc))
[⚙️ assert] edited longest ago
✅ got: ((last-edited-at asc))
[⚙️ assert] by name, descending
✅ got: ((display-name desc))
[⚙️ assert] by name, ascending
✅ got: ((display-name asc))
[⚙️ assert] most viewed first
✅ got: ((views desc))
[⚙️ assert] least viewed first
✅ got: ((views asc))
[🧪 test] the clause names a column and a direction, and nothing else
[⚙️ assert] the column is a symbol
✅ got: #t
[⚙️ assert] the direction is one of the two words
✅ got: #t
[⚙️ assert] and a clause is all there is to it
✅ got: 2
[🧪 test] something the page does not offer sorts the default way
[⚙️ assert] an unknown sort falls back
✅ got: ((last-edited-at desc))
[⚙️ assert] so does an empty one
✅ got: ((last-edited-at desc))
[🧪 test] a sort that is spelled like SQL is not passed through
[⚙️ assert] "views desc; DROP TABLE songs" sorts by default
✅ got: ((last-edited-at desc))
[⚙️ assert] "display-name asc --" sorts by default
✅ got: ((last-edited-at desc))
[⚙️ assert] "(drop-table)" sorts by default
✅ got: ((last-edited-at desc))
[⚙️ assert] "views\") desc" sorts by default
✅ got: ((last-edited-at desc))
ℹ️ info - ran 2 tasks in: 0 seconds, 5042 microseconds
running unit tests from file: about-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 384536129 (replay with VERITAS_SEED=384536129)
+----------------------------------------------+
[📑 suite] The word the link is offered in
[🧪 test] ja_JP has a word for it
[⚙️ assert] the label is translated
✅ got: #t
[🧪 test] en_US has a word for it
[⚙️ assert] the label is translated
✅ got: #t
[🧪 test] nl_NL has a word for it
[⚙️ assert] the label is translated
✅ got: #t
[🧪 test] es_ES has a word for it
[⚙️ assert] the label is translated
✅ got: #t
+----------------------------------------------+
[📑 suite] The order the page says things in
[🧪 test] the list stands under the sentence that introduces it
[⚙️ assert] the introduction comes first
✅ got: #t
[🧪 test] the account of the place comes before the ask
[⚙️ assert] nothing is asked for before anything is said
✅ got: #t
[🧪 test] the promises keep the order they were written in
[⚙️ assert] each one follows the one before it
✅ got: #t
+----------------------------------------------+
[📑 suite] What the page says the project is
[🧪 test] it ends on an invitation
[⚙️ assert] the last line is the invitation
✅ got: #t
[🧪 test] it introduces the list of what a reader can do
[⚙️ assert] the list is introduced
✅ got: #t
[🧪 test] it names what the project is
[⚙️ assert] the community is named
✅ got: #t
[⚙️ assert] and what it works towards
✅ got: #t
[🧪 test] it says what the project is built on
[⚙️ assert] the language is named
✅ got: #t
[⚙️ assert] and so is the architecture
✅ got: #t
+----------------------------------------------+
[📑 suite] The pages of an instance that asks for nothing
[🧪 test] the about page asks for nothing
[⚙️ assert] there is no control
✅ got: #f
[⚙️ assert] and none of the words that are on one
✅ got: #f
[⚙️ assert] and nothing about what the money pays for
✅ got: #f
[🧪 test] and the front page asks for nothing either
[⚙️ assert] there is no control
✅ got: #f
[⚙️ assert] and none of the words that are on one
✅ got: #f
[🧪 test] what the pages are for is still said
[⚙️ assert] the promises are still made
✅ got: #t
[⚙️ assert] and the front page still invites
✅ got: #t
+----------------------------------------------+
[📑 suite] What the page tells a crawler
[🧪 test] the description is the page's own one
[⚙️ assert] a search result shows the community
✅ got: #t
[🧪 test] the page says what kind of page it is
[⚙️ assert] the page states its own type
✅ got: #t
[⚙️ assert] and names the community as its subject
✅ got: #t
[🧪 test] the title names the community
[⚙️ assert] the page is titled
✅ got: #t
+----------------------------------------------+
[📑 suite] The words the two pages share
[🧪 test] the one ask is the same control on both pages
[⚙️ assert] the about page asks
✅ got: #t
[⚙️ assert] and so does the front page
✅ got: #t
[⚙️ assert] offered in the project's own words
✅ got: #t
[🧪 test] the account of the project belongs to the about page
[⚙️ assert] the front page is still the collection
✅ got: #f
[🧪 test] both pages name the place the same way
[⚙️ assert] the about page says it
✅ got: #t
[⚙️ assert] and so does the front page
✅ got: #t
[🧪 test] both pages close on the same invitation
[⚙️ assert] the about page invites
✅ got: #t
[⚙️ assert] and so does the front page
✅ got: #t
+----------------------------------------------+
[📑 suite] The link to the page
[🧪 test] every page offers it
[⚙️ assert] the footer links to it
✅ got: #t
[⚙️ assert] and says where it leads
✅ got: #t
+----------------------------------------------+
[📑 suite] The front page as a way in
[🧪 test] the search control carries the words to the collection
[⚙️ assert] the form names the collection
✅ got: #t
[⚙️ assert] and the field its words are read from
✅ got: #t
[🧪 test] a page with no artists to show is still the whole page
[⚙️ assert] no heading over nothing
✅ got: #f
[🧪 test] both shelves of the collection are shown, songs first
[⚙️ assert] the songs are there
✅ got: #t
[⚙️ assert] and so are the artists
✅ got: #t
[⚙️ assert] in the order they are read
✅ got: #t
[⚙️ assert] with a way to the rest of them
✅ got: #t
[🧪 test] the first screen says what is in the place
[⚙️ assert] the summary is read under the tagline
✅ got: #t
[⚙️ assert] and it is read after it
✅ got: #t
+----------------------------------------------+
[📑 suite] What the page promises a reader can do
[🧪 test] “Learn through curated resources that con…” is promised
[⚙️ assert] it is an item of the list
✅ got: #t
[⚙️ assert] and it is said once
✅ got: 1
[🧪 test] “Contribute by adding new compositions, a…” is promised
[⚙️ assert] it is an item of the list
✅ got: #t
[⚙️ assert] and it is said once
✅ got: 1
[🧪 test] “Organize information with structured met…” is promised
[⚙️ assert] it is an item of the list
✅ got: #t
[⚙️ assert] and it is said once
✅ got: 1
[🧪 test] “Discover music from diverse genres and t…” is promised
[⚙️ assert] it is an item of the list
✅ got: #t
[⚙️ assert] and it is said once
✅ got: 1
ℹ️ info - ran 9 tasks in: 1 seconds, -238475 microseconds
running unit tests from file: controller-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 384536129 (replay with VERITAS_SEED=384536129)
+----------------------------------------------+
[📑 suite] The guard a mistyped address reaches
[🧪 test] a lookup that found an empty list is a lookup that found nothing
[⚙️ assert] an empty list is answered like #f
✅ got: 404
[🧪 test] a lookup that found nothing is answered with a 404
[⚙️ assert] it raises rather than returning nothing
✅ got: #t
[⚙️ assert] with the code artanis renders a page for
✅ got: 404
[⚙️ assert] in the shape artanis reads: code, name, message, arguments
✅ got: #t
[⚙️ assert] the message is a format string
✅ got: #t
[⚙️ assert] and its arguments come as a list
✅ got: #t
[🧪 test] a row that was found is handed on as it is
[⚙️ assert] the very row comes back, not a copy
✅ got: #t
[⚙️ assert] and nothing about it is rewritten
✅ got: ((identifier . 1c9a5b7e-2f3a-4c5d-9e0f-1a2b3c4d5e6f) (display-name . blue));;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;; or pass the --no-auto-compile argument to disable.
;;; compiling /etc/byggsteg/job-clone/wikimusic/trunk/env.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/env.scm.go
;;; compiling ./test/veritas/unit/views-spec.scm
;;; compiling ./test/support/deployment.scm
;;; compiling ./lib/wikimusic/config.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/lib/wikimusic/config.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/test/support/deployment.scm.go
;;; compiling ./lib/wikimusic/html.scm
WARNING: (hygguile hygguile): imported module (hygguile components select) overrides core binding `select'
;;; compiling ./lib/wikimusic/seo.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/lib/wikimusic/seo.scm.go
WARNING: (wikimusic html): imported module (hygguile hygguile) overrides core binding `select'
WARNING: (wikimusic html): `get-short-commit-sha' imported from both (kracht prelude) and (hygguile hygguile)
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/lib/wikimusic/html.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/test/veritas/unit/views-spec.scm.go
WARNING: (wikimusic html): `get-short-commit-sha' imported from both (kracht prelude) and (hygguile hygguile)
WARNING: (wikimusic html): imported module (hygguile hygguile) overrides core binding `select'
;;; compiling ./test/veritas/unit/domain-spec.scm
;;; compiling ./lib/wikimusic/domain.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/lib/wikimusic/domain.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/test/veritas/unit/domain-spec.scm.go
;;; compiling ./test/veritas/unit/about-spec.scm
;;; compiling ./app/views/about.scm
;;; compiling ./lib/wikimusic/prose.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/lib/wikimusic/prose.scm.go
;;; compiling ./app/views/index.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/app/views/index.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/app/views/about.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/test/veritas/unit/about-spec.scm.go
;;; compiling ./test/veritas/unit/controller-spec.scm
;;; compiling ./lib/wikimusic/controller.scm
;;; compiling ./lib/wikimusic/sqlite/util.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/lib/wikimusic/sqlite/util.scm.go
;;; compiling ./lib/wikimusic/sqlite/comment.scm
;;; compiling ./lib/wikimusic/domain/comment.scm
;;; compiling ./lib/wikimusic/domain/repo.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/lib/wikimusic/domain/repo.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/lib/wikimusic/domain/comment.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/lib/wikimusic/sqlite/comment.scm.go
;;; compiling ./lib/wikimusic/auth.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/lib/wikimusic/auth.scm.go
;;; compiling ./app/views/error.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/app/views/error.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/lib/wikimusic/controller.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/test/veritas/unit/controller-spec.scm.go
;;; compiling ./test/veritas/unit/assets-spec.scm
;;; compiling ./resources/assets/fetch.scm
;;; compiled
[⚙️ assert] what it is called does not decide what it returns
✅ got: #t
[🧪 test] the answer says what was looked for, and where
[⚙️ assert] the message names the kind of thing and the identifier
✅ got: no genre with the identifier a-genre-that-is-not-there
+----------------------------------------------+
[📑 suite] The ownership half of who may change a row
[🧪 test] the super grant changes any row, whoever made it
[⚙️ assert] a row another user created
✅ got: #t
[⚙️ assert] and a row of its own
✅ got: #t
[🧪 test] a contributor does not change a row somebody else made
[⚙️ assert] someone else's row is refused
✅ got: #f
[🧪 test] a row that names no creator is only the super grant's to change
[⚙️ assert] a row with no creator is refused
✅ got: #f
[⚙️ assert] while the super grant may still change it
✅ got: #t
[🧪 test] a contributor changes the row they made
[⚙️ assert] their own row is theirs to change
✅ got: #t
ℹ️ info - ran 2 tasks in: 0 seconds, 4223 microseconds
running unit tests from file: assets-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 384536129 (replay with VERITAS_SEED=384536129)
+----------------------------------------------+
[📑 suite] A face is named after what it carries
[🧪 test] the family, the subset and the slope are all in the name
[⚙️ assert] a straight face names no slope
✅ got: intelonemono-latin.woff2
[⚙️ assert] a sloped one says so
✅ got: plusjakartasans-latin-italic.woff2
[⚙️ assert] and a subset that is not latin is kept apart
✅ got: intelonemono-symbols2-italic.woff2
+----------------------------------------------+
[📑 suite] An icon set is copied with what is served of it
[🧪 test] the face names the file that is beside it, and only it
[⚙️ assert] the woff2 clause ends the list
✅ got: #t
[⚙️ assert] the older woff is not named
✅ got: #t
[⚙️ assert] nor the ttf
✅ got: #t
[⚙️ assert] nor the svg
✅ got: #t
[🧪 test] a stylesheet with nothing to prune is left alone
[⚙️ assert] the text comes back as it went in
✅ got: @font-face {
font-family: "Phosphor";
src:
url("./Phosphor.woff2") format("woff2");
font-weight: normal;
font-style: normal;
font-display: block;
}
.ph {
font-family: "Phosphor" !important;
line-height: 1;
}
[🧪 test] what is left is still a stylesheet
[⚙️ assert] the braces still balance
✅ got: 2
[⚙️ assert] and they close as often
✅ got: 2
[⚙️ assert] the face keeps its family
✅ got: #t
[⚙️ assert] and the class the glyphs are worn with
✅ got: #t
[⚙️ assert] no clause is left dangling
✅ got: #t
+----------------------------------------------+
[📑 suite] A fetched stylesheet names the files beside it
[🧪 test] the address of the host it came from is gone
[⚙️ assert] no gstatic face is asked for
✅ got: #t
[⚙️ assert] nor any other absolute address
✅ got: #t
[⚙️ assert] the file beside it is named instead
✅ got: #t
[🧪 test] every face the answer named is a face to fetch
[⚙️ assert] three faces, three files
✅ got: ((https://fonts.gstatic.com/s/intelonemono/v25/aaa111.woff2 . intelonemono-symbols2-italic.woff2) (https://fonts.gstatic.com/s/intelonemono/v25/bbb222.woff2 . intelonemono-latin.woff2) (https://fonts.gstatic.com/s/plusjakartasans/v9/ccc333.woff2 . plusjakartasans-latin-italic.woff2))
[🧪 test] what the face says about itself is kept
[⚙️ assert] the format stays on the line
✅ got: #t
[⚙️ assert] so does what the face asks of the reader
✅ got: #t
[⚙️ assert] and the range it carries
✅ got: #t
[⚙️ assert] the line saying which subset follows
✅ got: #t
[⚙️ assert] and the stylesheet is as long as it was
✅ got: 27
[🧪 test] each face is named for the block it stands in
[⚙️ assert] the addresses and the names line up
✅ got: ((https://fonts.gstatic.com/s/intelonemono/v25/aaa111.woff2 . intelonemono-symbols2-italic.woff2) (https://fonts.gstatic.com/s/intelonemono/v25/bbb222.woff2 . intelonemono-latin.woff2) (https://fonts.gstatic.com/s/plusjakartasans/v9/ccc333.woff2 . plusjakartasans-latin-italic.woff2))
ℹ️ info - ran 3 tasks in: 0 seconds, 21809 microseconds
running unit tests from file: error-pages-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 384536129 (replay with VERITAS_SEED=384536129)
+----------------------------------------------+
[📑 suite] What an error page says
[🧪 test] a status with no wording of its own still describes itself
[⚙️ assert] an unnamed status is named in its headline
✅ got: #t
[⚙️ assert] and it still has an explanation
✅ got: #t
[⚙️ assert] which is not the wording of a status that has one
✅ got: #t
[🧪 test] an error page describes what the reader can do
[⚙️ assert] a 500 offers to be tried again
✅ got: #t
[⚙️ assert] a 404 points at what is still there
✅ got: #t
[🧪 test] a page is drawn in the tone its class of refusal is read in
[⚙️ assert] a 502 is read as a 500
✅ got: warning
[⚙️ assert] a 503 is read as a 500
✅ got: warning
[⚙️ assert] a 418 is read as a 400
✅ got: plugs
[⚙️ assert] a 451 is read as a 400
✅ got: plugs
[⚙️ assert] a request that timed out has a page
✅ got: #t
[🧪 test] a page leads with a headline of its own
[⚙️ assert] a 404 has a headline
✅ got: #t
[⚙️ assert] and something to explain itself
✅ got: #t
[⚙️ assert] the two codes do not share wording
✅ got: #t
[⚙️ assert] nor do their explanations
✅ got: #t
+----------------------------------------------+
[📑 suite] The classes an error page asks for
[🧪 test] every class the page names is one the sheets define
[⚙️ assert] no class is a no-op on the page
✅ got: ()
[⚙️ assert] and the page does name a fair few
✅ got: #t
+----------------------------------------------+
[📑 suite] Rendering an error page
[🧪 test] the wording is translated through the procedure it is given
[⚙️ assert] the headline arrives wrapped
✅ got: #t
[⚙️ assert] and so does the detail
✅ got: #t
[🧪 test] the page is serialized the way the rest of the site is
[⚙️ assert] inline script survives the serializer
✅ got: #t
[⚙️ assert] and is not escaped into nonsense
✅ got: #t
[🧪 test] a reader who is signed in is not invited to sign in again
[⚙️ assert] the navigation differs with the session
✅ got: #t
[🧪 test] the reader is offered a way out
[⚙️ assert] a link to /
✅ got: #t
[⚙️ assert] a link to /songs
✅ got: #t
[⚙️ assert] a link to /artists
✅ got: #t
[⚙️ assert] a link to /genres
✅ got: #t
[🧪 test] the page is a whole document of the site's own shell
[⚙️ assert] it starts with a doctype
✅ got: #t
[⚙️ assert] it is titled a WikiMusic page
✅ got: #t
[⚙️ assert] it links the site's stylesheet
✅ got: #t
[⚙️ assert] it carries the navigation
✅ got: #t
[⚙️ assert] and the footer
✅ got: #t
[🧪 test] the page says which status it is
[⚙️ assert] a 400 page shows its code
✅ got: #t
[⚙️ assert] a 400 page leads with its own wording
✅ got: #t
[⚙️ assert] a 400 page is drawn with a glyph
✅ got: #t
[⚙️ assert] a 401 page shows its code
✅ got: #t
[⚙️ assert] a 401 page leads with its own wording
✅ got: #t
[⚙️ assert] a 401 page is drawn with a glyph
✅ got: #t
[⚙️ assert] a 403 page shows its code
✅ got: #t
[⚙️ assert] a 403 page leads with its own wording
✅ got: #t
[⚙️ assert] a 403 page is drawn with a glyph
✅ got: #t
[⚙️ assert] a 404 page shows its code
✅ got: #t
[⚙️ assert] a 404 page leads with its own wording
✅ got: #t
[⚙️ assert] a 404 page is drawn with a glyph
✅ got: #t
[⚙️ assert] a 408 page shows its code
✅ got: #t
[⚙️ assert] a 408 page leads with its own wording
✅ got: #t
[⚙️ assert] a 408 page is drawn with a glyph
✅ got: #t
[⚙️ assert] a 500 page shows its code
✅ got: #t
[⚙️ assert] a 500 page leads with its own wording
✅ got: #t
[⚙️ assert] a 500 page is drawn with a glyph
✅ got: #t
ℹ️ info - ran 3 tasks in: 1 seconds, -317449 microseconds
running unit tests from file: auth-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 384536129 (replay with VERITAS_SEED=384536129)
+----------------------------------------------+
[📑 suite] Passwords on file
[🧪 test] the same password hashed twice is never the same hash
[⚙️ assert] the salt is drawn fresh every time
✅ got: #t
[🧪 test] a hash names the scheme it was derived with
[⚙️ assert] an argon2id hash says so
✅ got: argon2id
[⚙️ assert] and carries iterations, memory, lanes, salt and key
✅ got: 6
[⚙️ assert] a pbkdf2 hash says so
✅ got: pbkdf2-sha256
[⚙️ assert] and carries iterations, salt and key
✅ got: 4
[🧪 test] the recorded cost is at least the cost that was chosen
[⚙️ assert] argon2id does at least two passes
✅ got: #t
[⚙️ assert] and asks for at least 19 MiB a pass
✅ got: #t
[⚙️ assert] pbkdf2 does at least 210000 iterations
✅ got: #t
+----------------------------------------------+
[📑 suite] Reading a session
[🧪 test] every way of failing is the same noerror decrypting token: misc-error: (#f ~A (open-envelope: not a bewaking envelope (expected BWK3).) #f)error decrypting token: misc-error: (#f ~A (open-envelope: not a bewaking envelope (expected BWK3).) #f)
[⚙️ assert] no token at all
✅ got: #f
[⚙️ assert] a false token
✅ got: #f
[⚙️ assert] an empty cookie
✅ got: #f
[⚙️ assert] a cookie that is not even an envelope
✅ got: #f
[⚙️ assert] a cookie of some other shape
✅ got: #f
[🧪 test] an expired session is no session
[⚙️ assert] a validity that is already behind it
✅ got: #f
[🧪 test] a token that has been altered does not openerror decrypting token: misc-error: (#f ~A (bewaking: the sealed data could not be opened: unknown, retired or wrong key, or the data was altered.) #f)error decrypting token: misc-error: (#f ~A (bewaking: the sealed data could not be opened: unknown, retired or wrong key, or the data was altered.) #f)
[⚙️ assert] a truncated token
✅ got: #f
[⚙️ assert] a token with something appended
✅ got: #f
[🧪 test] a token sealed with the project's keys names its owner
[⚙️ assert] the owner's identifier comes back
✅ got: 8b3f6a1e-1c2d-4e5f-8a9b-0c1d2e3f4a5b
[⚙️ assert] and the permissions it was sealed with
✅ got: (wikimusic:song-create)
[⚙️ assert] the payload carries its own expiry
✅ got: #t
[🧪 test] a token sealed under another key is not ourserror decrypting token: misc-error: (#f ~A (bewaking: the sealed data could not be opened: unknown, retired or wrong key, or the data was altered.) #f)error decrypting token: misc-error: (#f ~A (bewaking: the sealed data could not be opened: unknown, retired or wrong key, or the data was altered.) #f)
[⚙️ assert] a token sealed with a key we do not hold
✅ got: #f
[⚙️ assert] nor one signed with another
✅ got: #f
[🧪 test] a route's permission has to be one the session holds
[⚙️ assert] the permission it holds is granted
✅ got: #t
[⚙️ assert] and so is a set it holds in full
✅ got: #t
[⚙️ assert] one it does not hold is refused
✅ got: #f
[⚙️ assert] with no permission asked for, a session is enough
✅ got: #t
+----------------------------------------------+
[📑 suite] The permissions column
[🧪 test] a row written before the change still yields its permissions
[⚙️ assert] a quasiquoted list is unwrapped
✅ got: (wikimusic:song-create)
[⚙️ assert] the long spelling of it too
✅ got: (wikimusic:song-create)
[🧪 test] anything that is not a list of permissions is an empty list
[⚙️ assert] an empty column
✅ got: ()
[⚙️ assert] no column at all
✅ got: ()
[⚙️ assert] an unreadable column
✅ got: ()
[⚙️ assert] a bare symbol
✅ got: ()
[⚙️ assert] a string
✅ got: ()
[🧪 test] a list of permissions is read as written
[⚙️ assert] one permission
✅ got: (wikimusic:song-create)
[⚙️ assert] several, in order
✅ got: (wikimusic:song-create wikimusic:artist-delete)
[🧪 test] the column is read, never run
[⚙️ assert] a form naming a procedure comes back as data
✅ got: (system rm -rf /)
[⚙️ assert] and so does a lambda
✅ got: (lambda (x) x)
+----------------------------------------------+
[📑 suite] Checking a password
[🧪 test] a password hashed before the change still verifies
[⚙️ assert] the right password still signs in
✅ got: #t
[⚙️ assert] the wrong one still does not
✅ got: #f
[⚙️ assert] and the row is recognisable as an old one
✅ got: #t
[⚙️ assert] while a derived hash is not
✅ got: #f
[🧪 test] a hash was only derived from the one password
[⚙️ assert] a password missing its last character
✅ got: #f
[⚙️ assert] a password with the wrong case
✅ got: #f
[⚙️ assert] the empty password
✅ got: #f
[🧪 test] the password a hash was derived from verifies
[⚙️ assert] the preferred scheme round trips
✅ got: #t
[⚙️ assert] and so does the fallback scheme
✅ got: #t
[⚙️ assert] the salt column no longer decides
✅ got: #t
[🧪 test] a hash that cannot be read is not a match
[⚙️ assert] no hash at all
✅ got: #f
[⚙️ assert] an argon2id salt that is not hexadecimal
✅ got: #f
[⚙️ assert] an argon2id cost that is not a number
✅ got: #f
[⚙️ assert] an argon2id hash with a field missing
✅ got: #f
[⚙️ assert] a pbkdf2 hash with a field missing
✅ got: #f
[🧪 test] a row with no usable hash is refused rather than crashed on
[⚙️ assert] no hash is not a legacy hash
✅ got: #f
[⚙️ assert] nor is something that is not a string
✅ got: #f
ℹ️ info - ran 4 tasks in: 0 seconds, 88595 microseconds
running unit tests from file: guitarpro-view-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 384536129 (replay with VERITAS_SEED=384536129)
+----------------------------------------------+
[📑 suite] What a tab's own header is shown as
[🧪 test] a key is listed by the name of the key and not the count
[⚙️ assert] two flats is B flat
✅ got: Bb
[🧪 test] the numbers a header always carries are always listed
[⚙️ assert] the measures
✅ got: 42
[⚙️ assert] the tracks
✅ got: 3
[🧪 test] a field its author left empty is not listed at all
[⚙️ assert] an empty artist
✅ got: #f
[⚙️ assert] an album that was never read
✅ got: #f
[⚙️ assert] a key with no name
✅ got: #f
[🧪 test] every field a tab's author filled in is listed
[⚙️ assert] the title
✅ got: a title
[⚙️ assert] the artist
✅ got: an artist
[⚙️ assert] the album
✅ got: an album
[⚙️ assert] who tabbed it
✅ got: a tabber
[🧪 test] a tempo is written as a reader reads it
[⚙️ assert] a tempo in beats per minute
✅ got: 132 bpm
+----------------------------------------------+
[📑 suite] The section a version's tab is offered in
[🧪 test] and the offer to draw it here, which is a button and not a script
[⚙️ assert] the button
✅ got: #t
[🧪 test] a version carrying no tab is offered none
[⚙️ assert] a field a reader never touched
✅ got: ()
[⚙️ assert] and a version whose tab is not a tab at all
✅ got: ()
[🧪 test] a version carrying a tab offers it for download
[⚙️ assert] the link to the file
✅ got: #t
[⚙️ assert] and the name it is saved under
✅ got: #t
[🧪 test] a tab whose header cannot be read says so and is still a download
[⚙️ assert] the sentence
✅ got: #t
[🧪 test] each version's section is named after the version it is
[⚙️ assert] the score of the second version
✅ got: #t
[⚙️ assert] and not the first version's
✅ got: #t
[🧪 test] the words the player shows are the page's own
[⚙️ assert] while it loads
✅ got: #t
[⚙️ assert] once it is drawn
✅ got: #t
[⚙️ assert] and when it cannot be drawn
✅ got: #t
[⚙️ assert] the state while loading is a place the script reaches
✅ got: #t
[⚙️ assert] and the state once drawn
✅ got: #t
[⚙️ assert] and the state that failed
✅ got: #t
[🧪 test] the controls and the score are on the page before they are used
[⚙️ assert] the controls start hidden
✅ got: #t
[⚙️ assert] the place a score is drawn in
✅ got: #t
[🧪 test] playing and stopping are offered once there is something to play
[⚙️ assert] playing
✅ got: #t
[⚙️ assert] and stopping
✅ got: #t
+----------------------------------------------+
[📑 suite] The name a tab is saved under
[🧪 test] the characters a file name cannot hold are replaced
[⚙️ assert] a song whose name holds a slash and a colon
✅ got: A-B- C-D-.gp5
[🧪 test] the name says which song and which version it is
[⚙️ assert] the two together
✅ got: A Song - v1.gp5
[🧪 test] a name is still made of nothing
[⚙️ assert] a version with no name of its own
✅ got: wikimusic-tab.gp5
[⚙️ assert] and a song the page has not read yet
✅ got: wikimusic-tab.gp5
ℹ️ info - ran 3 tasks in: 0 seconds, 26631 microseconds
running unit tests from file: guitarpro-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 384536129 (replay with VERITAS_SEED=384536129)
+----------------------------------------------+
[📑 suite] What a base64 text spells
[🧪 test] a text that is not base64 is refused rather than guessed at
[⚙️ assert] a character outside the alphabet
✅ success catching error: misc-error: (#f base64-decode-string: not a base64 character ~S (*) #f)
[⚙️ assert] a text that ends in a lone character
✅ success catching error: misc-error: (#f base64-decode-string: the text ends in a lone base64 character () #f)
[🧪 test] a text whose bytes are known decodes to them
[⚙️ assert] two characters
✅ got: h
[⚙️ assert] three characters
✅ got: hi
[⚙️ assert] five characters
✅ got: hello
[⚙️ assert] six characters is two whole groups
✅ got: hello!
[🧪 test] a text broken across lines is read as one
[⚙️ assert] whitespace between the characters is ignored
✅ got: hello
[🧪 test] the encoding a browser does round-trips through the decoder
[⚙️ assert] one character, the shortest text that needs padding
✅ got: a
[⚙️ assert] one whole group of three
✅ got: abc
[⚙️ assert] a word
✅ got: wikimusic
[⚙️ assert] a text whose bytes are not its characters
✅ got: a title with an accent: café
+----------------------------------------------+
[📑 suite] The key a header names
[🧪 test] each signature of the fifteen is named
[⚙️ assert] no accidentals is C
✅ got: C
[⚙️ assert] two flats is B flat
✅ got: Bb
[⚙️ assert] one sharp is G
✅ got: G
[⚙️ assert] seven sharps is C sharp
✅ got: C#
[⚙️ assert] seven flats is C flat
✅ got: Cb
[🧪 test] a number no signature has is not named at all
[⚙️ assert] one flat too many
✅ got: #f
[⚙️ assert] and one sharp too many
✅ got: #f
+----------------------------------------------+
[📑 suite] What the header of a Guitar Pro 5 file declares
[🧪 test] every field of a written file is read back
[⚙️ assert] the release
✅ got: (5 10)
[⚙️ assert] the title
✅ got: a title
[⚙️ assert] the artist, two fields along
✅ got: an artist
[⚙️ assert] the notice lines, in order
✅ got: (first notice second notice)
[⚙️ assert] the lyrics
✅ got: (the words of the song)
[⚙️ assert] the tempo
✅ got: 132
[⚙️ assert] the key signature
✅ got: -2
[⚙️ assert] the key it names
✅ got: Bb
[⚙️ assert] the measures
✅ got: 42
[⚙️ assert] the tracks
✅ got: 3
[🧪 test] a header written by a release after 5.0 is read the same way
[⚙️ assert] the tempo of a 5.1 file
✅ got: 155
[⚙️ assert] the track count of a 5.1 file
✅ got: 5
[⚙️ assert] the tempo of a 5.0 file
✅ got: 155
[⚙️ assert] the track count of a 5.0 file
✅ got: 5
[🧪 test] a field whose two lengths disagree is refused
[⚙️ assert] a string that claims a length it does not have
✅ got: #f
[🧪 test] the reader consumes exactly the header and nothing more
[⚙️ assert] the plain file
✅ got: 1063
[⚙️ assert] a file with no title
✅ got: 1056
[⚙️ assert] a file with a long title
✅ got: 1093
[⚙️ assert] a file with two notice lines
✅ got: 1092
[⚙️ assert] a file of the earlier release
✅ got: 1058
[⚙️ assert] a file with numbers at their widest
✅ got: 1063
[🧪 test] a file whose counts cannot be true is refused
[⚙️ assert] a negative measure count
✅ got: #f
[🧪 test] a file of the right generation that is cut short is refused
[⚙️ assert] a header missing its last fields
✅ got: #f
[⚙️ assert] a file missing its whole header
✅ got: #f
[🧪 test] a file that is not a readable Guitar Pro 5 file is answered with #f
[⚙️ assert] nothing at all
✅ got: #f
[⚙️ assert] a text file
✅ got: #f
[⚙️ assert] a pdf
✅ got: #f
[⚙️ assert] a Guitar Pro 4 file
✅ got: #f
+----------------------------------------------+
[📑 suite] What a data URL holds
[🧪 test] a version's own file is read through its data URL
[⚙️ assert] the title
✅ got: through a data url
[⚙️ assert] the tempo
✅ got: 90
[🧪 test] an empty value is not a data URL
[⚙️ assert] the empty string
✅ got: #f
[⚙️ assert] nor is a path
✅ got: #f
[🧪 test] a data URL that holds something other than base64 holds no bytes
[⚙️ assert] a text data URL
✅ got: #f
[⚙️ assert] a base64 text that does not decode
✅ got: #f
[🧪 test] a base64 data URL is one, and its bytes come back
[⚙️ assert] a file posted by a browser
✅ got: #t
[⚙️ assert] the bytes after the comma
✅ got: hi
ℹ️ info - ran 4 tasks in: 0 seconds, 26201 microseconds
running unit tests from file: config-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 384536129 (replay with VERITAS_SEED=384536129)
+----------------------------------------------+
[📑 suite] Where the instance reads what it says about itself
[🧪 test] a variable the deployment set is the one read
[⚙️ assert] the deployment's own value wins
✅ got: https://pingwing.jointhefreeworld.org
[🧪 test] a variable the deployment did not set falls back
[⚙️ assert] the project's own value is used
✅ got: the project's own value
+----------------------------------------------+
[📑 suite] The manual is read where the code is
[🧪 test] the manual's address is the deployment's, or the README beside its code
[⚙️ assert] the manual follows the code
✅ got: https://codeberg.org/jjba23/wikimusic/src/branch/trunk/README.org
+----------------------------------------------+
[📑 suite] Where the interface's own files are read from
[🧪 test] a file named with a leading slash is one file
[⚙️ assert] the leading slash is not doubled
✅ got: /css/wikimusic.olive.min.css
[🧪 test] a deployment that serves them elsewhere says where
[⚙️ assert] every file hangs off the host it named
✅ got: https://assets.example.org/wikimusic/vendor/fonts/lucida.css
[🧪 test] a host written with a trailing slash does not double it
[⚙️ assert] one slash between the two
✅ got: https://assets.example.org/wikimusic/favicon.ico
[🧪 test] an instance serving its own reads them off itself
[⚙️ assert] a path on this instance
✅ got: /vendor/fonts/lucida.css
[⚙️ assert] and the page's own stylesheet with it
✅ got: /css/wikimusic.olive.min.css
+----------------------------------------------+
[📑 suite] The picture a page is announced with
[🧪 test] a path is turned into an address of the instance serving it
[⚙️ assert] the path is joined onto the origin
✅ got: https://example.org/img/cover.jpg
[🧪 test] an address the deployment gave is left alone
[⚙️ assert] an address is already one
✅ got: https://pictures.example.org/cover.jpg
[🧪 test] and with no host to build one on, no address is invented
[⚙️ assert] no origin, no address
✅ got: #f
+----------------------------------------------+
[📑 suite] The control an instance turns off
[🧪 test] and may say so in words
[⚙️ assert] false
✅ got: #f
[⚙️ assert] No, however it is capitalised
✅ got: #f
[⚙️ assert] off, with room around it
✅ got: #f
[⚙️ assert] 0
✅ got: #f
[🧪 test] an instance that raises nothing says so with #f
[⚙️ assert] the switch itself
✅ got: #f
[🧪 test] and words that are not a no leave it on
[⚙️ assert] yes
✅ got: #t
[⚙️ assert] or the switch itself
✅ got: #t
[🧪 test] an instance that says nothing about it asks
[⚙️ assert] the ask is shown unless it says otherwise
✅ got: #t
+----------------------------------------------+
[📑 suite] The addresses the instance offers
[🧪 test] the copyright line names somebody
[⚙️ assert] the holder is named
✅ got: #t
[🧪 test] each one is an absolute address
[⚙️ assert] where the source is read
✅ got: #t
[⚙️ assert] where the manual is read
✅ got: #t
[⚙️ assert] where the licence is written out
✅ got: #t
[⚙️ assert] where a reader supports the project
✅ got: #t
[🧪 test] the mail an instance sends comes from an address
[⚙️ assert] an address, not a blank
✅ got: #t
[⚙️ assert] and a name beside it
✅ got: #t
ℹ️ info - ran 6 tasks in: 0 seconds, 24194 microseconds
running unit tests from file: sql-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 384536129 (replay with VERITAS_SEED=384536129)
+----------------------------------------------+
[📑 suite] Rendering a statement for the driver
[🧪 test] a value is rendered as a literal, and its quotes are doubled
[⚙️ assert] a string is quoted
✅ got: SELECT * FROM "songs" WHERE "display_name" = 'x'
[⚙️ assert] an apostrophe inside a value is doubled
✅ got: SELECT * FROM "songs" WHERE "display_name" = 'O''Brien'
[⚙️ assert] a value that means to end the string cannot
✅ got: SELECT * FROM "songs" WHERE "display_name" = '''; DROP TABLE users; --'
[⚙️ assert] so every quote it carries is paired
✅ got: 4
[🧪 test] a statement string is passed through untouched
[⚙️ assert] a plain string
✅ got: SELECT 1
[⚙️ assert] a statement with a quoted value of its own
✅ got: SELECT 'x'
[🧪 test] a number and a boolean are not quoted
[⚙️ assert] a number is written as itself
✅ got: SELECT * FROM "songs" WHERE "views" = 3
[⚙️ assert] a true value is written as 1
✅ got: SELECT * FROM "songs" WHERE "views" = 1
[🧪 test] column names are quoted as identifiers
[⚙️ assert] a hyphenated symbol is spelled underscore
✅ got: UPDATE "users" SET "password" = 'argon2id$x' WHERE "identifier" = 'id-1'
+----------------------------------------------+
[📑 suite] Matching a term
[🧪 test] a LIKE condition renders as LIKE, with its term bound
[⚙️ assert] a wildcard term
✅ got: SELECT * FROM "songs" WHERE "display_name" LIKE '%x%'
[🧪 test] the search statement a builder cannot write is still kracht's
[⚙️ assert] the apostrophe in the term is doubled
✅ got: #t
[⚙️ assert] no placeholder survives the substitution
✅ got: #f
[⚙️ assert] and the paging is written as numbers
✅ got: #t
+----------------------------------------------+
[📑 suite] Matching a set of identifiers
[🧪 test] an IN clause binds one value per identifier, in order
[⚙️ assert] two identifiers
✅ got: SELECT * FROM "songs" WHERE "identifier" IN ('a', 'b')
[🧪 test] and a NOT IN over an empty set matches everything
[⚙️ assert] NOT IN () becomes a true predicate
✅ got: SELECT * FROM "songs" WHERE 1 = 1
[🧪 test] an empty set matches nothing rather than everything
[⚙️ assert] IN () becomes a false predicate
✅ got: SELECT * FROM "songs" WHERE 1 = 0
+----------------------------------------------+
[📑 suite] Sorting
[🧪 test] a direction that is not a direction is an error
[⚙️ assert] so an unknown word cannot reach the statement
✅ got: #t
[🧪 test] both spellings of a sort are accepted
[⚙️ assert] one clause, not yet wrapped
✅ got: ((display-name asc))
[⚙️ assert] a clause list is left as it is
✅ got: ((views desc) (display-name asc))
[⚙️ assert] and nothing sorts by nothing
✅ got: ()
[🧪 test] a clause renders its column and its direction
[⚙️ assert] two clauses, in order
✅ got: "views" DESC, "display_name" ASC
[⚙️ assert] a column with no direction renders bare
✅ got: "display_name"
[⚙️ assert] and a hyphen becomes an underscore there too
✅ got: "last_edited_at" DESC
+----------------------------------------------+
[📑 suite] Shaping a row
[🧪 test] an attribute for an unlisted column cannot reach the statement
[⚙️ assert] a key wikimusic never names is dropped
✅ got: ((display-name . x))
[🧪 test] a row holding none of the columns is an error
[⚙️ assert] an insert with no columns is refused
✅ got: #t
[🧪 test] a column the attributes do not carry is simply left out
[⚙️ assert] so the table's own default can stand
✅ got: ((display-name . x))
[🧪 test] only the named columns survive, in the named order
[⚙️ assert] the columns decide, not the attributes
✅ got: ((views . 2) (display-name . x))
+----------------------------------------------+
[📑 suite] Accounting for placeholders
[🧪 test] the number of values has to match the number of placeholders
[⚙️ assert] a value too few is an error rather than a guess
✅ got: #t
[⚙️ assert] a value too many is an error too
✅ got: #t
[⚙️ assert] a placeholder with no value is refused, not left behind
✅ got: #t
[🧪 test] a rendered statement holds no placeholder any more
[⚙️ assert] no question mark survives the substitution
✅ got: #f
[⚙️ assert] and the rest of the statement is intact
✅ got: #t
[🧪 test] something that is neither a query nor a string is refused
[⚙️ assert] a number is not a statement
✅ got: #t
[⚙️ assert] nor is a symbol
✅ got: #t
ℹ️ info - ran 6 tasks in: 0 seconds, 25681 microseconds
finished running tests
/root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/resources/assets/fetch.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/test/veritas/unit/assets-spec.scm.go
;;; compiling ./test/veritas/unit/error-pages-spec.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/test/veritas/unit/error-pages-spec.scm.go
;;; compiling ./test/veritas/unit/auth-spec.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/test/veritas/unit/auth-spec.scm.go
;;; compiling ./test/veritas/unit/guitarpro-view-spec.scm
;;; compiling ./app/views/song-content-view.scm
;;; compiling ./lib/wikimusic/guitarpro.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/lib/wikimusic/guitarpro.scm.go
;;; compiling ./lib/wikimusic/domain/guitar-chord-guide.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/lib/wikimusic/domain/guitar-chord-guide.scm.go
WARNING: (app views song-content-view): imported module (hygguile hygguile) overrides core binding `select'
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/app/views/song-content-view.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/test/veritas/unit/guitarpro-view-spec.scm.go
;;; compiling ./test/veritas/unit/guitarpro-spec.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/test/veritas/unit/guitarpro-spec.scm.go
;;; compiling ./test/veritas/unit/config-spec.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/test/veritas/unit/config-spec.scm.go
;;; compiling ./test/veritas/unit/sql-spec.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/wikimusic/trunk/test/veritas/unit/sql-spec.scm.go
--------------------------------------------------------------
Maak 0.14.0: the infinitely extensible command runner
Loading tasks from Maak file: /etc/byggsteg/job-clone/wikimusic/trunk/maak.scm
Executing Maak tasks: test
--------------------------------------------------------------
=> Running Maak task: test
Run the project's test suite, one spec at a time, from test/veritas.
Executing: guix time-machine --channels=channels.scm -- shell -m manifest.scm -- guile --fresh-auto-compile -L ./lib -L ./test -L . -c '(load "env.scm")(begin (setlocale LC_ALL "C.UTF-8") (use-modules (veritas runner)) (run-tests))'
→ running command: cd /etc/byggsteg/job-clone/wikimusic/trunk && sudo herd enable wikimusic-daemon || true && sudo herd restart wikimusic-daemon || true
Enabled service wikimusic-daemon.
Service wikimusic-daemon has been started.
→ running command: cd /etc/byggsteg/job-clone/wikimusic/trunk && sudo maak deploy
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
Warning (emacs): Cannot fontify source block (htmlize.el >= 1.34 required). Falling back to plain text. (see ‘org-html-htmlize-output-type’)
finished publishing Wikimusic manual
--------------------------------------------------------------
Maak 0.14.0: the infinitely extensible command runner
Loading tasks from Maak file: /etc/byggsteg/job-clone/wikimusic/trunk/maak.scm
Executing Maak tasks: deploy
--------------------------------------------------------------
=> Running Maak task: deploy
Deploy the project's documentation.
The manual is rendered from the README and served under `manuals/wikimusic',
which is where a reader of the site is sent.
Execute command:
guix time-machine --channels=channels.scm -- shell -m manifest.scm -- emacs -Q --batch --eval '(progn (require (quote ox-html)) (setq org-html-prefer-user-labels t) (find-file "./README.org") (org-html-export-to-html) (message "finished publishing Wikimusic manual"))'
Executing: guix time-machine --channels=channels.scm -- shell -m manifest.scm -- emacs -Q --batch --eval '(progn (require (quote ox-html)) (setq org-html-prefer-user-labels t) (find-file "./README.org") (org-html-export-to-html) (message "finished publishing Wikimusic manual"))'
removed '/srv/http/jointhefreeworld.org/manuals/wikimusic/index.html'
renamed 'README.html' -> '/srv/http/jointhefreeworld.org/manuals/wikimusic/index.html'