starting new job...
→ running command: dir='/etc/byggsteg/job-clone//lucidplan/trunk'
branch='trunk'
if ! command -v git >/dev/null 2>&1; then
echo 'byggsteg: git is not on this deployment PATH, so the clone cannot be updated' >&2
exit 1
fi
if ! cd "$dir"; then
echo "byggsteg: cannot enter the clone $dir" >&2
exit 1
fi
root=$(git rev-parse --show-toplevel 2>/dev/null)
if [ "$root" != "$(pwd -P)" ]; then
echo "byggsteg: $dir is not a git checkout; remove it and the next run clones it again" >&2
exit 1
fi
if ! origin=$(git remote get-url origin 2>/dev/null); then
echo "byggsteg: $dir has no origin remote to fetch $branch from" >&2
exit 1
fi
before=$(git rev-parse --short HEAD 2>/dev/null) || before=none
attempt=1
while :; do
if GIT_TERMINAL_PROMPT=0 git fetch --quiet origin "+refs/heads/$branch:refs/remotes/origin/$branch"; then
break
fi
if [ "$attempt" -ge 3 ]; then
echo "byggsteg: could not fetch $branch from $origin after 3 attempts; is the branch still there, and is the remote reachable?" >&2
exit 1
fi
echo "byggsteg: fetching $branch from $origin failed; retrying in $((attempt * 2))s" >&2
sleep $((attempt * 2))
attempt=$((attempt + 1))
done
if ! git checkout --quiet --force -B "$branch" FETCH_HEAD; then
echo "byggsteg: fetched $branch from $origin but could not check it out" >&2
exit 1
fi
after=$(git rev-parse --short HEAD)
if [ "$before" = "$after" ]; then
echo "byggsteg: $branch was already at $after"
else
echo "byggsteg: $branch moved from $before to $after"
fi
byggsteg: trunk moved from 61c2204 to e7d44ac
→ running command: cd /etc/byggsteg/job-clone/lucidplan/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/lucidplan/trunk && git log --name-status HEAD^..HEAD
commit e7d44ac9f6ec32f986067bd4b601549faf0c0c6b
Author: Josep Bigorra <jjbigorra@gmail.com>
Date: Wed Nov 4 23:09:24 2026 +0100
docs: Update visual identity
M README.org
A logo.svg
→ running command: cd /etc/byggsteg/job-clone/lucidplan/trunk && maak test
scanning directories for unit tests...
scanning present working directory for unit tests...
shuffled the files with seed 514633351 (replay with VERITAS_SEED=514633351)
found unit tests: (time-entry-spec.scm ticket-estimate-spec.scm burndown-spec.scm ticket-triage-spec.scm ticket-thread-spec.scm planning-poker-spec.scm)
running unit tests from file: time-entry-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 514633351 (replay with VERITAS_SEED=514633351)
+----------------------------------------------+
[📑 suite] what a ticket's time entries add up to
[🧪 test] a total reads as a duration and as hours
[⚙️ assert] one hundred and sixty-five minutes
✅ got: 2h 45m
[⚙️ assert] and as the hours a report adds up in
✅ got: 2.75
[🧪 test] a ticket nobody logged time on adds up to nothing
[⚙️ assert] no entries is no minutes
✅ got: 0
[🧪 test] a row that is not a duration does not break the sum
[⚙️ assert] a malformed row counts as nothing
✅ got: 120
[🧪 test] every entry counts toward the total
[⚙️ assert] two and a half hours over three days
✅ got: 165
+----------------------------------------------+
[📑 suite] a number of minutes, said to a reader
[🧪 test] a number that is not a duration is said as nothing
[⚙️ assert] no value answers the empty text
✅ got:
[⚙️ assert] a negative duration answers it too
✅ got:
[🧪 test] hours and minutes are said together
[⚙️ assert] an hour and a half
✅ got: 1h 30m
[🧪 test] less than an hour is said in minutes
[⚙️ assert] three quarters of an hour
✅ got: 45m
[🧪 test] nothing is said as nothing rather than as empty space
[⚙️ assert] zero minutes still reads as a duration
✅ got: 0m
[🧪 test] a whole number of hours is said in hours
[⚙️ assert] two hours
✅ got: 2h
+----------------------------------------------+
[📑 suite] a duration, read the ways it is written
[🧪 test] a duration is read in the words it is spoken in
[⚙️ assert] two hours, spelled out
✅ got: 120
[⚙️ assert] three quarters of an hour
✅ got: 45
[⚙️ assert] an abbreviation of an hour
✅ got: 60
[⚙️ assert] an abbreviation of minutes
✅ got: 15
[⚙️ assert] a whole day of work is a day
✅ got: 1440
[🧪 test] the case of what was typed does not matter
[⚙️ assert] capitals are the same duration
✅ got: 90
[🧪 test] space around the whole thing is not part of it
[⚙️ assert] a padded form still means its duration
✅ got: 30
[🧪 test] an hour and a half is ninety minutes however it is typed
[⚙️ assert] in hours, with a fraction
✅ got: 90
[⚙️ assert] in minutes alone
✅ got: 90
[⚙️ assert] as hours and minutes, run together
✅ got: 90
[⚙️ assert] as hours and minutes, with a space
✅ got: 90
[⚙️ assert] as a clock reading
✅ got: 90
[⚙️ assert] as a bare number of minutes
✅ got: 90
+----------------------------------------------+
[📑 suite] a number of minutes, added up in hours
[🧪 test] a whole number of hours is a whole decimal
[⚙️ assert] an hour is 1
✅ got: 1
[⚙️ assert] two hours is 2
✅ got: 2
[🧪 test] part of an hour is a fraction of it
[⚙️ assert] an hour and a half is 1.5
✅ got: 1.5
[⚙️ assert] three quarters is 0.75
✅ got: 0.75
[🧪 test] a number that is not a duration is zero hours
[⚙️ assert] no value answers zero
✅ got: 0
+----------------------------------------------+
[📑 suite] what is not a duration
[🧪 test] a clock reading is read as a clock, not as two numbers
[⚙️ assert] minutes past the hour are minutes
✅ got: #f
[⚙️ assert] a single minute digit is not a clock
✅ got: #f
[🧪 test] a day's worth is the ceiling
[⚙️ assert] more than a day is a typo
✅ got: #f
[⚙️ assert] a bare number past the ceiling is a typo
✅ got: #f
[🧪 test] no time logged is no entry
[⚙️ assert] an empty form is refused
✅ got: #f
[⚙️ assert] a form of nothing but space is refused
✅ got: #f
[⚙️ assert] no value at all is refused
✅ got: #f
[⚙️ assert] zero minutes is not time spent
✅ got: #f
[⚙️ assert] zero hours is not time spent either
✅ got: #f
[🧪 test] what names no duration at all is refused
[⚙️ assert] words are refused
✅ got: #f
[⚙️ assert] a negative duration is refused
✅ got: #f
[⚙️ assert] a unit nobody knows is refused
✅ got: #f
[⚙️ assert] a stray character is not skipped
✅ got: #f
[⚙️ assert] something that is not text is refused
✅ got: #f
ℹ️ info - ran 5 tasks in: 0 seconds, 62951 microseconds
running unit tests from file: ticket-estimate-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 514633351 (replay with VERITAS_SEED=514633351)
+----------------------------------------------+
[📑 suite] the changes a write to a ticket is recorded with
[🧪 test] a column the tracker does not watch is not a change
[⚙️ assert] the stamp is not a tracked field
✅ got: #f
[🧪 test] a field that moved is recorded with its two values
[⚙️ assert] the title, the label and both values
✅ got: ((title title a ticket another ticket))
[🧪 test] every tracked field has the name a reader knows it by
[⚙️ assert] the seven tracked fields are named
✅ got: ((title title) (description description) (ticket-status status) (ticket-type type) (priority priority) (estimate-points story points) (estimate-size size))
[🧪 test] several fields that moved are recorded one row each
[⚙️ assert] both estimates moved
✅ got: 2
[🧪 test] an estimate that was never made is not a change
[⚙️ assert] no estimate answers no change
✅ got: ()
[🧪 test] the two ways of saying nothing are the same state
[⚙️ assert] a missing value and an empty text agree
✅ got:
[⚙️ assert] and both are recorded as the empty text
✅ got:
[⚙️ assert] a number is recorded as its text
✅ got: 21
[🧪 test] an estimate that was cleared is a change
[⚙️ assert] the estimate it had is recorded
✅ got: (3 )
[🧪 test] a ticket submitted back unchanged is not an edit
[⚙️ assert] nothing moved, so nothing is recorded
✅ got: ()
+----------------------------------------------+
[📑 suite] an estimate changed from the ticket's own page
[🧪 test] a story point the menu offered is accepted
[⚙️ assert] the change is the column and its value
✅ got: ((estimate-points . 8))
[🧪 test] clearing an estimate is a change the menu offers
[⚙️ assert] the empty row changes the ticket
✅ got: ((estimate-points . ))
[🧪 test] a size nobody offered is refused
[⚙️ assert] a size off the ladder changes nothing
✅ got: #f
[🧪 test] a size the menu offered is accepted
[⚙️ assert] the change is the column and its value
✅ got: ((estimate-size . m))
[⚙️ assert] clearing a size is offered too
✅ got: ((estimate-size . ))
[🧪 test] a story point nobody offered is refused
[⚙️ assert] a value off the ladder changes nothing
✅ got: #f
[⚙️ assert] words change nothing
✅ got: #f
+----------------------------------------------+
[📑 suite] a ticket's story-point estimate
[🧪 test] the ladder is the one the menus and the endpoints share
[⚙️ assert] the points are the shipped sequence
✅ got: (0 1 2 3 5 8 13 21 34)
[🧪 test] a number on the team's ladder is taken as that number
[⚙️ assert] a value the menu offered is accepted
✅ got: 5
[⚙️ assert] a number arrives as a number as well
✅ got: 13
[⚙️ assert] space around it is not part of it
✅ got: 3
[⚙️ assert] zero is an estimate somebody made
✅ got: 0
[🧪 test] a number the team does not estimate with is refused
[⚙️ assert] a value off the ladder is refused
✅ got: #f
[⚙️ assert] a negative estimate is refused
✅ got: #f
[⚙️ assert] words are refused
✅ got: #f
[⚙️ assert] something that is not text is refused
✅ got: #f
[🧪 test] an estimate nobody made is no estimate, not zero
[⚙️ assert] an empty form is no estimate
✅ got: #f
[⚙️ assert] a blank form is no estimate
✅ got: #f
[⚙️ assert] no value at all is no estimate
✅ got: #f
+----------------------------------------------+
[📑 suite] a ticket's t-shirt size
[🧪 test] a size on the ladder is taken as it is stored
[⚙️ assert] a size the menu offered is accepted
✅ got: l
[⚙️ assert] a size typed in capitals means the same
✅ got: xl
[⚙️ assert] space around it is not part of it
✅ got: m
[🧪 test] a size nobody offers is refused
[⚙️ assert] a size off the ladder is refused
✅ got: #f
[⚙️ assert] the ladder is the shipped sequence
✅ got: (xs s m l xl xxl)
[🧪 test] no size is no estimate
[⚙️ assert] an empty form is no size
✅ got: #f
[⚙️ assert] a value that is not text is no size
✅ got: #f
[🧪 test] each size is shown to a reader in capitals
[⚙️ assert] the smallest is shown in capitals
✅ got: XS
[⚙️ assert] the middle of the ladder
✅ got: M
[⚙️ assert] the largest is shown in capitals
✅ got: XXL
[⚙️ assert] a size nobody knows is shown as itself
✅ got: huge
ℹ️ info - ran 4 tasks in: 0 seconds, 42183 microseconds
running unit tests from file: burndown-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 514633351 (replay with VERITAS_SEED=514633351)
+----------------------------------------------+
[📑 suite] the line a sprint is burnt down along
[🧪 test] work finished on a day is burnt on that day, not before
[⚙️ assert] nothing is done on the first day
✅ got: 13
[⚙️ assert] five points are gone on the second
✅ got: 8
[⚙️ assert] and they stay gone on the third
✅ got: 8
[🧪 test] a ticket taken out of the sprint stops counting
[⚙️ assert] the scope still holds it on the first day
✅ got: 13
[⚙️ assert] it is gone from the second day on
✅ got: 5
[⚙️ assert] and nothing but the done ticket is left
✅ got: 0
[🧪 test] a sprint whose end is before its beginning is not drawn
[⚙️ assert] a backwards sprint draws nothing
✅ got: ()
[🧪 test] an unestimated ticket adds nothing to the sum
[⚙️ assert] the unsized ticket is not counted
✅ got: 5
[🧪 test] the summary is the last day said once
[⚙️ assert] thirteen committed
✅ got: 13
[⚙️ assert] five done
✅ got: 5
[⚙️ assert] eight left
✅ got: 8
[🧪 test] the point a day started with is the scope and what was done
[⚙️ assert] thirteen points were committed
✅ got: 13
[⚙️ assert] five of them were done
✅ got: 5
[🧪 test] a ticket that was reopened is not still counted as done
[⚙️ assert] five points are burnt on the second day
✅ got: 8
[⚙️ assert] and they come back when the ticket does
✅ got: 13
[🧪 test] a day is drawn up to today and no further
[⚙️ assert] three days of a five-day sprint
✅ got: (2026-10-01 2026-10-02 2026-10-03)
[🧪 test] the committed line falls evenly to nothing on the last day
[⚙️ assert] the first day is the whole commitment
✅ got: 13.0
[⚙️ assert] the second day is three quarters of it
✅ got: 9.75
[⚙️ assert] the third day is half of it
✅ got: 6.5
[🧪 test] a closed sprint is drawn to its last day
[⚙️ assert] all five days, read afterwards
✅ got: 5
[🧪 test] a sprint with no dates is not drawn
[⚙️ assert] no days to draw
✅ got: ()
[🧪 test] a sprint with nothing in it is a flat line at nothing
[⚙️ assert] every day is zero
✅ got: (0 0 0)
+----------------------------------------------+
[📑 suite] how a deadline stands, read against today
[🧪 test] a ticket with no deadline has no state
[⚙️ assert] no deadline answers nothing
✅ got: #f
[⚙️ assert] a deadline that is not a day answers nothing
✅ got: #f
[🧪 test] today is today
[⚙️ assert] the day itself
✅ got: due-today
[🧪 test] a day within the warning is due soon
[⚙️ assert] a week out is close enough to worry about
✅ got: due-soon
[⚙️ assert] tomorrow is close enough too
✅ got: due-soon
[🧪 test] a day that has passed is overdue
[⚙️ assert] yesterday is overdue
✅ got: overdue
[🧪 test] the warning is a week, and it is the same week everywhere
[⚙️ assert] the threshold the pages share
✅ got: 7
[🧪 test] a day further out is simply scheduled
[⚙️ assert] the day after the warning
✅ got: scheduled
+----------------------------------------------+
[📑 suite] the day a submitted date names
[🧪 test] a day written the way a date field writes it is read
[⚙️ assert] an ordinary day
✅ got: 2026-10-27
[⚙️ assert] space around it is not part of it
✅ got: 2026-10-27
[🧪 test] a day that does not exist is refused
[⚙️ assert] the 31st of February is not a day
✅ got: #f
[⚙️ assert] the 31st of April is not a day
✅ got: #f
[⚙️ assert] the 29th of February 2026 is not a day
✅ got: #f
[⚙️ assert] the 29th of February 2028 is a leap day
✅ got: 2028-02-29
[🧪 test] what is not a date is refused
[⚙️ assert] an empty form is no date
✅ got: #f
[⚙️ assert] no value at all is no date
✅ got: #f
[⚙️ assert] a date without its day is refused
✅ got: #f
[⚙️ assert] a date written the other way round is refused
✅ got: #f
[⚙️ assert] a month that does not exist is refused
✅ got: #f
+----------------------------------------------+
[📑 suite] the states a sprint can be in
[🧪 test] only one state is the one a team is in
[⚙️ assert] active is running
✅ got: #t
[⚙️ assert] planned is not
✅ got: #f
[🧪 test] the three states are the shipped ladder
[⚙️ assert] planned, active, closed
✅ got: (planned active closed)
[🧪 test] a stretch of days has to run forwards
[⚙️ assert] an end before its beginning is refused
✅ got: #f
[⚙️ assert] an undated sprint is allowed
✅ got: #t
[⚙️ assert] an open-ended sprint is allowed
✅ got: #t
[🧪 test] a state on the ladder is taken as it is stored
[⚙️ assert] an ordinary state
✅ got: active
[⚙️ assert] a state typed in capitals means the same
✅ got: closed
[🧪 test] a state nobody offers is refused
[⚙️ assert] a state off the ladder is refused
✅ got: #f
[⚙️ assert] something that is not text is refused
✅ got: #f
+----------------------------------------------+
[📑 suite] counting the days between two of them
[🧪 test] a value that is not a day is no difference
[⚙️ assert] two things that are not days
✅ got: #f
[🧪 test] the same day is no days apart
[⚙️ assert] a day and itself
✅ got: 0
[🧪 test] a day and its number are each other's
[⚙️ assert] the number of a day names it back
✅ got: 2026-10-27
[🧪 test] a week is seven days
[⚙️ assert] seven days
✅ got: 7
[🧪 test] month lengths and leap years do not disturb the count
[⚙️ assert] across the end of a short month
✅ got: 7
[⚙️ assert] across a leap day
✅ got: 2
[⚙️ assert] across a new year
✅ got: 2
[🧪 test] the answer is negative when the second day is earlier
[⚙️ assert] a week the other way
✅ got: -7
ℹ️ info - ran 5 tasks in: 0 seconds, 67676 microseconds
running unit tests from file: ticket-triage-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 514633351 (replay with VERITAS_SEED=514633351)
+----------------------------------------------+
[📑 suite] the order a list is asked for in
[🧪 test] a keyword the pages offer becomes an ORDER BY
[⚙️ assert] the title, A to Z
✅ got: ((title asc))
[⚙️ assert] the priority, highest first
✅ got: ((priority desc))
[🧪 test] a keyword nobody offers falls back to the last edited first
[⚙️ assert] an unknown order is the default one
✅ got: ((updated-at desc))
[⚙️ assert] and so is no order at all
✅ got: ((updated-at desc))
+----------------------------------------------+
[📑 suite] the list a project's tickets move through
[🧪 test] a project with none uses the instance's
[⚙️ assert] a project that says nothing falls back to the instance
✅ got: ((todo To-do anchor ⚓ open) (work-in-progress Work in Progress gear-fine ⚙️ open) (in-review In Review list-magnifying-glass 🔍 open) (done Done check ✅ done) (rejected Rejected x ❌ rejected))
[🧪 test] a project that could not be read is not an error
[⚙️ assert] no project at all falls back to the instance
✅ got: ((todo To-do anchor ⚓ open) (work-in-progress Work in Progress gear-fine ⚙️ open) (in-review In Review list-magnifying-glass 🔍 open) (done Done check ✅ done) (rejected Rejected x ❌ rejected))
[🧪 test] a project with a list of its own uses it
[⚙️ assert] the project's own list is the one read
✅ got: (todo shipped)
+----------------------------------------------+
[📑 suite] statuses written by hand
[🧪 test] a field left out takes the default the rest of the code reads
[⚙️ assert] a bucket nothing knows is read as open
✅ got: open
[🧪 test] the bucket is read
[⚙️ assert] a status in the done bucket says so
✅ got: done
[⚙️ assert] a status in the rejected bucket says so
✅ got: rejected
[🧪 test] text that names nothing is not a list of statuses
[⚙️ assert] an empty block answers #f
✅ got: #f
[⚙️ assert] a block of notes alone answers #f
✅ got: #f
[🧪 test] each field of an entry is read
[⚙️ assert] the label is read
✅ got: To-do
[⚙️ assert] the icon is read
✅ got: anchor
[⚙️ assert] the glyph is read
✅ got: ⚓
[🧪 test] the values are read in the order they were written
[⚙️ assert] the read-back values keep their order
✅ got: (todo done rejected)
[🧪 test] a note and a blank line are skipped rather than read as statuses
[⚙️ assert] the comment is not a status
✅ got: #f
[⚙️ assert] no status was invented by the blank line
✅ got: 3
+----------------------------------------------+
[📑 suite] an inline change from the ticket's own page
[🧪 test] with no project list the instance's own is the ladder
[⚙️ assert] the first status of the instance's list is accepted
✅ got: #t
[🧪 test] a status the project does not move through is refused
[⚙️ assert] a status invented by hand changes nothing
✅ got: #f
[🧪 test] a field a ticket has no ladder for is refused
[⚙️ assert] the priority is not changed this way
✅ got: #f
[🧪 test] a type is checked against the types a ticket has
[⚙️ assert] a type on the ladder is accepted
✅ got: ((ticket-type . bug))
[⚙️ assert] a type nothing offers is refused
✅ got: #f
[⚙️ assert] the types are the ones the schema holds
✅ got: (task bug story spike time-box)
[🧪 test] a status the project moves through is accepted
[⚙️ assert] the change is the column and its new value
✅ got: ((ticket-status . done))
+----------------------------------------------+
[📑 suite] the assignee a form submitted
[🧪 test] no assignee is the absence of one, not an unknown user
[⚙️ assert] an empty submission leaves the ticket as it was
✅ got: #f
[🧪 test] an id that was not offered is refused
[⚙️ assert] an id no menu offered is not an assignee
✅ got: #f
[⚙️ assert] a value that is not text is not an assignee
✅ got: #f
[🧪 test] an id that was offered is answered
[⚙️ assert] a known id is taken as it was submitted
✅ got: user-1
+----------------------------------------------+
[📑 suite] a status that is not on the list
[🧪 test] is not in any bucket's list
[⚙️ assert] the done bucket holds the statuses that are done
✅ got: (done)
[🧪 test] reads as itself when there is no label for it
[⚙️ assert] the value stands in for the label
✅ got: polishing
[⚙️ assert] there is no spec for it
✅ got: #f
[🧪 test] is still a ticket somebody is working on
[⚙️ assert] an unknown status is bucketed as open
✅ got: open
ℹ️ info - ran 6 tasks in: 0 seconds, 39293 microseconds
running unit tests from file: ticket-thread-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 514633351 (replay with VERITAS_SEED=514633351)
+----------------------------------------------+
[📑 suite] how big a file is, said in one line
[🧪 test] a size nobody knows is not a size
[⚙️ assert] no size answers nothing
✅ got:
[🧪 test] larger files are said in the unit a reader expects
[⚙️ assert] a couple of kilobytes
✅ got: 2.0 KB
[⚙️ assert] a couple of megabytes
✅ got: 2.0 MB
[🧪 test] bytes are said as bytes
[⚙️ assert] a small file is counted in bytes
✅ got: 512 B
[⚙️ assert] an empty file is counted too
✅ got: 0 B
+----------------------------------------------+
[📑 suite] the type a file is served as
[🧪 test] anything a header cannot carry becomes the generic type
[⚙️ assert] a line break would split the header
✅ got: application/octet-stream
[⚙️ assert] a quoted type is not a type
✅ got: application/octet-stream
[⚙️ assert] no type at all is the generic one
✅ got: application/octet-stream
[⚙️ assert] an empty type is the generic one
✅ got: application/octet-stream
[🧪 test] a media type is kept
[⚙️ assert] a type a header can carry survives
✅ got: text/plain
[⚙️ assert] a type the application made up survives
✅ got: application/vnd.oasis.opendocument.text
+----------------------------------------------+
[📑 suite] the thread a ticket's comments make
[🧪 test] an id read back from the database names the same comment
[⚙️ assert] a numeric parent names the same comment
✅ got: 1
[🧪 test] a thread that was written wrong still terminates
[⚙️ assert] a cycle is answered at the depth reached
✅ got: 2
[⚙️ assert] a missing parent is answered at the root
✅ got: 0
[🧪 test] a comment nothing answers has no children
[⚙️ assert] the last word is the last word
✅ got: ()
[🧪 test] the comments on the ticket itself are the ones it hangs from
[⚙️ assert] the roots are the comments with no parent
✅ got: (c1 c4)
[🧪 test] the depth a comment is indented by is how far down it is
[⚙️ assert] a comment on the ticket is not indented
✅ got: 0
[⚙️ assert] a reply is indented once
✅ got: 1
[⚙️ assert] a reply to a reply is indented twice
✅ got: 2
[🧪 test] a reply is drawn under what it answers
[⚙️ assert] the answer to the first word
✅ got: (c2)
[⚙️ assert] nothing answers the answer but one
✅ got: (c3)
+----------------------------------------------+
[📑 suite] how a download is named
[🧪 test] a path in the submitted name never reaches the header
[⚙️ assert] the plain form is cut to the last name
✅ got: hosts
[🧪 test] both the plain and the encoded name are carried
[⚙️ assert] the disposition carries the two names
✅ got: (attachment (filename . my report.pdf) (filename* . UTF-8''my%20report.pdf))
[🧪 test] the disposition is a type and its parameters
[⚙️ assert] the type is the attachment disposition
✅ got: attachment
+----------------------------------------------+
[📑 suite] the name a file is served under
[🧪 test] an empty name is still a name
[⚙️ assert] nothing submitted answers the generic
✅ got: attachment
[⚙️ assert] a name of nothing but space answers it too
✅ got: attachment
[⚙️ assert] no name at all answers it too
✅ got: attachment
[🧪 test] what a header cannot carry is replaced
[⚙️ assert] quotes and backslashes do not survive
✅ got: my _report_.pdf
[⚙️ assert] a line break is replaced
✅ got: line_break.txt
[🧪 test] only the last component of a submitted path is kept
[⚙️ assert] a path is cut to its last component
✅ got: passwd
[⚙️ assert] a separator a path could be written with does not survive
✅ got: #f
[🧪 test] a name is cut to a length a header can carry
[⚙️ assert] a very long name is shortened
✅ got: #t
[🧪 test] a name that is just a name is kept
[⚙️ assert] a plain name survives
✅ got: report.pdf
ℹ️ info - ran 5 tasks in: 0 seconds, 26898 microseconds
running unit tests from file: planning-poker-spec.scm, entrypoint: spec
ℹ️ info - shuffled with seed 514633351 (replay with VERITAS_SEED=514633351)
+----------------------------------------------+
[📑 suite] a card of one of the decks
[🧪 test] a card nobody deals is refused
[⚙️ assert] a number off the ladder
✅ got: #f
[⚙️ assert] a size off the ladder
✅ got: #f
[⚙️ assert] a card of the other deck
✅ got: #f
[⚙️ assert] an empty form plays nothing
✅ got: #f
[⚙️ assert] nothing at all plays nothing
✅ got: #f
[🧪 test] a card of the room's deck is taken as the deck spells it
[⚙️ assert] a story point
✅ got: 5
[⚙️ assert] a t-shirt size is lowercased
✅ got: m
[⚙️ assert] space around a card is not part of it
✅ got: 8
[🧪 test] the cards are dealt in the ladder's own order
[⚙️ assert] a hand of points opens on nothing
✅ got: (0 1 2 3 5 8 13 21 34)
[⚙️ assert] a hand of sizes opens on the smallest
✅ got: (xs s m l xl xxl)
[⚙️ assert] a deck nobody deals deals nothing
✅ got: ()
[🧪 test] the sizes sort by the ladder and not by their letters
[⚙️ assert] the smallest is the first rung
✅ got: 0
[⚙️ assert] the largest is the last
✅ got: 5
[⚙️ assert] a card nobody deals has no rung
✅ got: #f
[🧪 test] a card is shown with the face the ladder gives it
[⚙️ assert] a size is shown in capitals
✅ got: XXL
[⚙️ assert] a number is already what it says
✅ got: 13
+----------------------------------------------+
[📑 suite] the seat a browser holds without an account
[🧪 test] a seat is a room and a secret
[⚙️ assert] one seat reads back
✅ got: ((room-a . secret-1))
[⚙️ assert] two seats read back in written order
✅ got: ((room-a . secret-1) (room-b . secret-2))
[🧪 test] a value that is not a seat is not a seat
[⚙️ assert] no cookie at all
✅ got: ()
[⚙️ assert] an empty cookie
✅ got: ()
[⚙️ assert] an entry without a secret
✅ got: ()
[⚙️ assert] an entry with an empty room
✅ got: ()
[⚙️ assert] a malformed entry is skipped, not obeyed
✅ got: ((room-b . secret-2))
[🧪 test] the number of seats a cookie holds is capped
[⚙️ assert] the cap is what the section says
✅ got: 8
[⚙️ assert] the newest seat is the one that is there
✅ got: secret-new
[🧪 test] a seat is found by the room it was taken at
[⚙️ assert] the seat at one room
✅ got: secret-2
[⚙️ assert] no seat at a room nobody sat at
✅ got: #f
[🧪 test] sitting at a second table does not cost the first seat
[⚙️ assert] the newer seat is written first
✅ got: room-b~secret-2|room-a~secret-1
[⚙️ assert] a seat taken again moves to the front
✅ got: room-a~secret-9|room-b~secret-2
+----------------------------------------------+
[📑 suite] what a browser may know about a card before the reveal
[🧪 test] a card is not answered while the cards are face down
[⚙️ assert] a point, not yet revealed
✅ got: #f
[⚙️ assert] a size, not yet revealed
✅ got: #f
[🧪 test] a card is answered once the room is revealed
[⚙️ assert] a point, revealed
✅ got: 5
[⚙️ assert] a size, revealed, in capitals
✅ got: M
[🧪 test] a seat that played nothing has nothing to show either way
[⚙️ assert] no card, revealed
✅ got: #f
[⚙️ assert] no card, unrevealed
✅ got: #f
+----------------------------------------------+
[📑 suite] the name a participant is known by
[🧪 test] the space around a name is not part of it
[⚙️ assert] a padded name is trimmed
✅ got: joe
[🧪 test] a name is capped because it is a label on a card
[⚙️ assert] a name at the cap is a name
✅ got: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[⚙️ assert] one character past it is not
✅ got: #f
[🧪 test] a name of nothing is no name
[⚙️ assert] an empty form
✅ got: #f
[⚙️ assert] a form of spaces
✅ got: #f
[⚙️ assert] nothing at all
✅ got: #f
[⚙️ assert] something that is not text
✅ got: #f
[🧪 test] a run of spaces inside a name is one space
[⚙️ assert] the words are kept, the gap is not
✅ got: joe the dev
+----------------------------------------------+
[📑 suite] what a table may write onto a ticket
[🧪 test] a round nobody played has nothing to write down
[⚙️ assert] no cards, no number
✅ got: #f
[🧪 test] a card the ladder does not hold is not a change
[⚙️ assert] a number the team does not estimate with
✅ got: #f
[⚙️ assert] a size nobody sizes at
✅ got: #f
[🧪 test] an agreed card is a change a ticket would accept
[⚙️ assert] the agreed points are a submitable change
✅ got: ((estimate-points . 8))
[⚙️ assert] and the agreed size is one too
✅ got: ((estimate-size . xl))
[🧪 test] the deck a table deals is the column a ticket carries
[⚙️ assert] points are the ticket's points
✅ got: estimate-points
[⚙️ assert] sizes are the ticket's size
✅ got: estimate-size
[⚙️ assert] a deck with no column has none
✅ got: #f
[🧪 test] a room that agreed on one card has a number to take
[⚙️ assert] the card everybody played
✅ got: 5
[⚙️ assert] the card most of it played
✅ got: 5
[⚙️ assert] a size is a card too
✅ got: m
[🧪 test] a room that split has nothing to write down
[⚙️ assert] an even split takes no number
✅ got: #f
[⚙️ assert] and the tally still names both
✅ got: (2 5)
+----------------------------------------------+
[📑 suite] the deck a table deals
[🧪 test] the decks are the two ladders a ticket is estimated on
[⚙️ assert] the two the section ships
✅ got: (points sizes)
[⚙️ assert] and their sizes are the ticket ladders
✅ got: (xs s m l xl xxl)
[⚙️ assert] and their points are too
✅ got: (0 1 2 3 5 8 13 21 34)
[🧪 test] a deck the table offers is taken as it is stored
[⚙️ assert] story points
✅ got: points
[⚙️ assert] t-shirt sizes
✅ got: sizes
[🧪 test] a deck is named in the words a reader is shown
[⚙️ assert] the numbers a team burns down
✅ got: story points
[⚙️ assert] what a first pass is written in
✅ got: t-shirt sizes
[🧪 test] a deck nobody deals is refused
[⚙️ assert] the fibonacci deck is not one of ours
✅ got: #f
[⚙️ assert] an empty form names no deck
✅ got: #f
[⚙️ assert] something that is not text names no deck
✅ got: #f
[🧪 test] a deck typed in capitals means the same
[⚙️ assert] capitals are the same deck
✅ got: points
+----------------------------------------------+
[📑 suite] the ticket a table is about
[🧪 test] a table opened for nothing is about no ticket
[⚙️ assert] a room with no ticket columns at all
✅ got: #f
[⚙️ assert] a project and no number
✅ got: #f
[⚙️ assert] a number and no project
✅ got: #f
[🧪 test] a table opened for a ticket answers which one
[⚙️ assert] the project and the number in it
✅ got: ((project . lucidplan) (number . 479))
+----------------------------------------------+
[📑 suite] what a round of cards adds up to
[🧪 test] a tally of sizes is counted too
[⚙️ assert] two sizes, in ladder order
✅ got: ((s . 1) (l . 1))
[🧪 test] a round nobody played agrees on nothing
[⚙️ assert] no cards, no agreement
✅ got: ()
[🧪 test] a round with no mean has none
[⚙️ assert] sizes have no mean
✅ got: #f
[⚙️ assert] no cards have no mean
✅ got: #f
[🧪 test] a spread is the two ends of the disagreement
[⚙️ assert] the lowest and the highest of the points
✅ got: ((low . 2) (high . 13))
[⚙️ assert] the ends of the sizes are sizes
✅ got: ((low . s) (high . xxl))
[🧪 test] a room that agrees has no spread
[⚙️ assert] one card is no spread
✅ got: #f
[⚙️ assert] the same card twice is no spread
✅ got: #f
[⚙️ assert] no cards is no spread
✅ got: #f
[🧪 test] the mean of a round of points is a number
[⚙️ assert] two cards average where they sit
✅ got: 6.5
[⚙️ assert] one card is its own mean
✅ got: 3.0
[🧪 test] the room agrees on the card most of it played
[⚙️ assert] the card played most often
✅ got: (5)
[🧪 test] a card nobody played is not a row of the tally
[⚙️ assert] two cards were played, in ladder order
✅ got: ((2 . 1) (5 . 2))
[🧪 test] a round nobody played has no tally
[⚙️ assert] no cards, no rows
✅ got: ()
[🧪 test] an even split is a split, not a decision
[⚙️ assert] both cards of a tie, in ladder order
✅ got: (2 5)
ℹ️ info - ran 8 tasks in: 0 seconds, 84572 microseconds
finished running tests
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;; or pass the --no-auto-compile argument to disable.
;;; compiling test/veritas/unit/time-entry-spec.scm
;;; compiling lib/lucidplan/domain.scm
;;; compiling lib/lucidplan/config.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/lucidplan/trunk/lib/lucidplan/config.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/lucidplan/trunk/lib/lucidplan/domain.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/lucidplan/trunk/test/veritas/unit/time-entry-spec.scm.go
;;; compiling test/veritas/unit/ticket-estimate-spec.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/lucidplan/trunk/test/veritas/unit/ticket-estimate-spec.scm.go
;;; compiling test/veritas/unit/burndown-spec.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/lucidplan/trunk/test/veritas/unit/burndown-spec.scm.go
;;; compiling test/veritas/unit/ticket-triage-spec.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/lucidplan/trunk/test/veritas/unit/ticket-triage-spec.scm.go
;;; compiling test/veritas/unit/ticket-thread-spec.scm
;;; compiling lib/lucidplan/domain/ticket-comment.scm
;;; compiling lib/lucidplan/domain/repo.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/lucidplan/trunk/lib/lucidplan/domain/repo.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/lucidplan/trunk/lib/lucidplan/domain/ticket-comment.scm.go
;;; compiling lib/lucidplan/attachments.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/lucidplan/trunk/lib/lucidplan/attachments.scm.go
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/lucidplan/trunk/test/veritas/unit/ticket-thread-spec.scm.go
;;; compiling test/veritas/unit/planning-poker-spec.scm
;;; compiled /root/.cache/guile/ccache/3.0-LE-8-4.7/etc/byggsteg/job-clone/lucidplan/trunk/test/veritas/unit/planning-poker-spec.scm.go
--------------------------------------------------------------
Maak 0.14.0: the infinitely extensible command runner
Loading tasks from Maak file: /etc/byggsteg/job-clone/lucidplan/trunk/maak.scm
Executing Maak tasks: test
--------------------------------------------------------------
=> Running Maak task: test
Run the test suite with veritas.
The tests live under `test/veritas/': `unit/' for the ones that run on every
change, and `benchmark/' for the ones that measure rather than assert, which
veritas keeps apart because they answer a different question and take a
different amount of time. The application's own directories are on the load
path, so a test names the module it tests the way the application does.
Executing: env VERITAS_TEST_TYPE=unit VERITAS_RUN_BENCHMARKS=true guix time-machine --channels=channels.scm -- shell -m manifest.scm -- guile --fresh-auto-compile -L . -L lib -L test -c '(begin (setlocale LC_ALL "C.UTF-8") (use-modules (veritas runner)) (run-tests))'
→ running command: cd /etc/byggsteg/job-clone/lucidplan/trunk && maak migrate
-------------------------------------------------
Starting Mutastructura: guile -L /gnu/store/dlg9fm51pz31zv0fbqq5svy7sh0dbs2h-profile/share/guile/site/3.0 -c ((@(mutastructura main) main)) --database sqlite3 --connection lucidplan.db --migrations /etc/byggsteg/job-clone/lucidplan/trunk/resources/migrations/sqlite --resources /gnu/store/dlg9fm51pz31zv0fbqq5svy7sh0dbs2h-profile/share/resources
---------------------------------------------------------
MUTASTRUCTURA: Schema Migrations tooling powered by Lisp
🏛️ M U T A S T R U C T U R A 🏛️
_ _ V E N I • V I D I • L I S P _ _
WARNING: Checksum mismatch for already applied migration 2026-04-01_10:52:00_init_lucidplan_schema.sql!
WARNING: Checksum mismatch for already applied migration 2026-05-22_11:21:00_drop_unique_constraint_human_id.sql!
WARNING: Checksum mismatch for already applied migration 2026-10-14_12:00:00_add_project_ticket_statuses.sql!
WARNING: Checksum mismatch for already applied migration 2026-10-22_12:00:00_add_ticket_estimates_collaboration_history.sql!
WARNING: Checksum mismatch for already applied migration 2026-10-27_12:00:00_add_sprints_milestones_time_entries.sql!
WARNING: Checksum mismatch for already applied migration 2026-10-27_13:00:00_add_planning_poker.sql!
WARNING: Checksum mismatch for already applied migration 2026-10-27_14:00:00_add_poker_item_ticket.sql!
WARNING: Checksum mismatch for already applied migration 2026-10-27_15:00:00_add_poker_room_ticket.sql!
FOUND MIGRATION HISTORY:
((id . 1) (name . "mutastructura-init.sql") (checksum . "9cc74e39062f44295eed10dcc318b67a87a2dc0ac9bc62eb76500fc4f3650e03") (applied-at . "2026-04-07 13:04:36"))
((id . 2) (name . "2026-04-01_10:52:00_init_lucidplan_schema.sql") (checksum . "f3923079248f1ffca1e9b06357e0a2207f07179609cbe24c44ab1108ed512593") (applied-at . "2026-04-07 13:11:37"))
((id . 3) (name . "2026-04-07_12:21:00_add_root_user.sql") (checksum . "7b09084eda456e679e753b07db590033604f1a92612160ab84f621405218b9b3") (applied-at . "2026-04-07 13:11:37"))
((id . 4) (name . "2026-05-22_11:21:00_drop_unique_constraint_human_id.sql") (checksum . "1ec83c352cd035fa547cc2f901ae01ab9dbb5c1cacb33d6fee2c683fa7f21e61") (applied-at . "2026-05-22 22:02:32"))
((id . 5) (name . "2026-10-14_12:00:00_add_project_ticket_statuses.sql") (checksum . "e3f1e0272a130ea622a137f106dbbd5986e85ae3732cfab84710f0e3cf53d867") (applied-at . "2026-10-14 11:52:12"))
((id . 6) (name . "2026-10-22_12:00:00_add_ticket_estimates_collaboration_history.sql") (checksum . "31de462a20b09362e9600ea0095f25285a87edf886bf29ef314b337014788dd3") (applied-at . "2026-10-22 18:30:25"))
((id . 7) (name . "2026-10-27_12:00:00_add_sprints_milestones_time_entries.sql") (checksum . "3e3c2a32f6c6871b78f74a8481f1c9bfeba95da302a9eab5f033b84cf5a33a4e") (applied-at . "2026-10-26 08:10:30"))
((id . 8) (name . "2026-10-27_13:00:00_add_planning_poker.sql") (checksum . "a3e14ee805b11306e176d4ec5c746b057633b8704034628afe0fdb749f01a1e5") (applied-at . "2026-10-27 20:24:22"))
((id . 9) (name . "2026-10-27_14:00:00_add_poker_item_ticket.sql") (checksum . "7b97f73c573ae9b4fc27d99429ef29bc5eb8e24790dd9a655543d9609a77d50f") (applied-at . "2026-10-27 20:24:22"))
((id . 10) (name . "2026-10-27_15:00:00_add_poker_room_ticket.sql") (checksum . "0b37bad93d5d9a4884765af4cf4e703df6991b5d207e0e88174398f9abb13792") (applied-at . "2026-10-27 20:24:22"))
((id . 11) (name . "2026-10-28_17:00:00_add_project_avatar.sql") (checksum . "80d4091f0ba7bc3be6678303f272f79bed9aa246ff5a4f2d535e772aa2764b27") (applied-at . "2026-10-28 19:33:34"))
((id . 12) (name . "2026-10-28_18:00:00_store_project_avatar_in_database.sql") (checksum . "6bbca6c6b86fcdbd1af22312c7f5da0f84d3d615c3389f3652420b765450b1df") (applied-at . "2026-10-28 19:33:34"))
((id . 13) (name . "2026-10-28_19:00:00_store_ticket_attachments_in_database.sql") (checksum . "287f4b621cac3766d5daa1ee2d9ea00668071a08c16e2c540f1b48ae60f7231a") (applied-at . "2026-10-28 19:33:34"))
((id . 14) (name . "2026-10-28_20:00:00_add_epics.sql") (checksum . "f5b3f8f655bdda335fed6ed4164917328a0f3911d8fa0a57caae082c4350d778") (applied-at . "2026-10-28 20:19:04"))
((id . 15) (name . "2026-10-28_21:00:00_add_labels_and_saved_filters.sql") (checksum . "0ab2d2f9dc0a0b2424907b378f69f6576959a210258f92f8100dc488f8851c93") (applied-at . "2026-10-28 20:19:04"))
---------------------------------------------------------
NOTHING TO DO!
CLOSING DATABASE...
--------------------------------------------------------------
Maak 0.14.0: the infinitely extensible command runner
Loading tasks from Maak file: /etc/byggsteg/job-clone/lucidplan/trunk/maak.scm
Executing Maak tasks: migrate
--------------------------------------------------------------
=> Running Maak task: migrate
Bring the database up to the schema the migrations describe.
Every migration in the migrations directory that the ledger has not recorded
yet is applied, in filename order, each inside its own transaction; a
database that is already up to date is left alone, and one that is not is
never half-migrated, because a migration that fails takes its own statements
back with it. The ledger is what makes that possible -- it is the record of
what has run, and mutastructura is the only thing that writes it -- so the
migrations are applied here and nowhere else, by hand or otherwise.
Executing: guix time-machine --channels=channels.scm -- shell -m manifest.scm -- mutastructura --database sqlite3 --connection lucidplan.db --migrations ./resources/migrations/sqlite
→ running command: cd /etc/byggsteg/job-clone/lucidplan/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’)
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 Lucidplan manual
--------------------------------------------------------------
Maak 0.14.0: the infinitely extensible command runner
Loading tasks from Maak file: /etc/byggsteg/job-clone/lucidplan/trunk/maak.scm
Executing Maak tasks: deploy
--------------------------------------------------------------
=> Running Maak task: deploy
Deploy the project's documentation.
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 Lucidplan 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 Lucidplan manual"))'
removed '/srv/http/jointhefreeworld.org/manuals/lucidplan/index.html'
renamed 'README.html' -> '/srv/http/jointhefreeworld.org/manuals/lucidplan/index.html'
→ running command: cd /etc/byggsteg/job-clone/lucidplan/trunk && sudo herd enable lucidplan-daemon || true && sudo herd restart lucidplan-daemon || true
Enabled service lucidplan-daemon.
Service lucidplan-daemon has been started.