Commit99c0c1e5Recorded1 Sep 2026Repositorysigil-css

Add a native kiln pipeline definition

Message

Defines CI as a kiln .kiln/ci.sgv pipeline with no wrapping shell script: deps / build / test / floor as four named steps of one job, plus an artifact step for the captured test output.

The header records what a step name does and does not buy today, why this is one node rather than three, and why the floor step is shell.

Changed
 .kiln/ci.sgv | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 111 insertions(+)
Diff
.kiln/ci.sgvadded
@@ -0,0 +1,111 @@
+1
;;; ci.sgv -- sigil-css CI, defined NATIVELY in kiln's job language.
+2
;;;
+3
;;; No `.kiln/ci.sh`. The steps below ARE the pipeline; there is no shell
+4
;;; script wrapping them. This is the pilot shape intended to be copied
+5
;;; across the extracted repos, so the reasoning is recorded here rather
+6
;;; than only in the task note.
+7
;;;
+8
;;; `on:` IS MANDATORY AND ITS ABSENCE IS SILENT. A workflow with no `on:`
+9
;;; matches no event, produces no error and no run, and reads exactly like
+10
;;; a controller fault rather than like this file.
+11
;;;
+12
;;; NO `branch:` FILTER ON `push`, deliberately. A filter would narrow
+13
;;; coverage to one ref; this library has none to spare. `(pull-request)`
+14
;;; is NOT declared: kiln's matcher accepts the trigger, but no run of
+15
;;; that kind has ever been observed on this controller, and declaring
+16
;;; coverage nobody has seen fire is how a green comes to mean less than
+17
;;; it looks. Note that unlike sigil-http and sigil-json this repo has no
+18
;;; `.woodpecker.yml` either -- it has never had CI of any kind.
+19
;;;
+20
;;; SINGLE NODE, FOUR NAMED STEPS -- not four jobs. Every node gets its
+21
;;; OWN workspace and its own delivered tree (runner.sgl `provide-source!`
+22
;;; per node), and `sigil deps install` writes its state under $HOME, not
+23
;;; into the workspace. Split across nodes, `build` and `test` would each
+24
;;; re-deliver the tree and depend on the worker's $HOME surviving between
+25
;;; leases -- an unstated dependency on worker statefulness -- or else ship
+26
;;; the whole dependency tree between nodes as artifacts, which is the
+27
;;; artifact fan-in path kiln's own `.kiln/ci.sgv` records as unproven.
+28
;;; Three nodes also take three leases against a pool of 4 at
+29
;;; max_concurrent 2, to buy status for stages that are strictly serial.
+30
;;;
+31
;;; WHAT A STEP NAME BUYS TODAY: readability, and nothing structural.
+32
;;; Measured 2026-09-01 on kiln ad9b9c5: `nodeexec.sgl` wraps a named
+33
;;; shell step in `##[kiln:section-start:<name>]`, while the log viewer's
+34
;;; parser (`web/views.sgl` `section-marker`) requires the prefix
+35
;;; `##[kiln:section-start ` -- space and timestamp, the LEGACY `.run`
+36
;;; grammar. The two do not meet, so a named step renders as a plain log
+37
;;; line, live and completed. The names are still worth having: they are
+38
;;; the contract a future comparison would rest on, a rename is a breaking
+39
;;; change even when it reads better, and they cost nothing to carry until
+40
;;; the grammar is reconciled. Do not assume they fold.
+41
;;;
+42
;;; THERE IS NO CHECK LEDGER HERE, AND THAT IS STRUCTURAL. The
+43
;;; `$KILN_ARTIFACTS/checks.ledger` contract that `kiln-diff-checks` and
+44
;;; the conversion plan's floors are built on is written entirely by a
+45
;;; repo's own `.kiln/ci.sh` -- `grep -rn checks.ledger src/` in kiln
+46
;;; returns nothing. A natively-defined pipeline emits no ledger by
+47
;;; construction. The `floor` step below is therefore NOT that contract
+48
;;; and must not be read as it: it asserts only that the suite ran and
+49
;;; reported at least the counts a green local run reported.
+50
;;;
+51
;;; TIMEOUT 1800, CHOSEN TO BE CLAMP-IMMUNE. `runner.sgl node-worker-fm`
+52
;;; applies (min declared ceiling) with NO diagnostic, where ceiling is
+53
;;; `safety.max_job_timeout`. The effective value is printed exactly once,
+54
;;; in the `Persistent worker ready ... timeout=N` line. 1800 is the
+55
;;; config default (`config.sgl:345`) and at or below every ceiling this
+56
;;; controller has been recorded with, so the declared value survives the
+57
;;; clamp whatever the key is set to. Local half-warm cost (shared $HOME
+58
;;; dep cache, fresh delivered tree) is far below it; a cold CI worker
+59
;;; will be slower, and 1800 is the headroom for that.
+60
+61
(pipeline ci
+62
on: #[ (push) (manual) ]
+63
+64
(job ci
+65
worker: (worker timeout: 1800)
+66
steps: #[
+67
+68
(shell "sigil deps install" name: deps)
+69
+70
(shell "sigil build" name: build)
+71
+72
;; `sigil test` is captured rather than piped: a pipeline's exit
+73
;; status is the LAST command's, so `sigil test | tee` reports tee's
+74
;; success and loses the failure. The `|| { rc=$?; ...; exit \"$rc\"; }`
+75
;; form keeps the real status while still printing the log.
+76
(shell "sigil test --no-color > kiln-test.out 2>&1 || { rc=$?; cat kiln-test.out; exit \"$rc\"; }
+77
cat kiln-test.out"
+78
name: test)
+79
+80
;; THE FLOOR. `sigil test` already exits 1 when it finds NO test
+81
;; files at all (measured), so this exists for the partial case:
+82
;; a file that stops matching the `test-*.sgl` / `*-test.sgl`
+83
;; discovery pattern is dropped SILENTLY and the run stays green on
+84
;; a smaller suite. Both numbers come from a green local run of
+85
;; ebd81a4: `Files: 1 of 1 run`, `Tests: 33 passed`.
+86
;;
+87
;; The counts are read with a numeric guard because a numeric
+88
;; comparison in POSIX sh fails OPEN on an empty or non-numeric
+89
;; value; an unreadable count is SETUP-FAILED (exit 2), which is a
+90
;; distinct outcome from the floor being breached (exit 1).
+91
;;
+92
;; NOTE FOR THE NEXT REPO: this step is the only part of the
+93
;; pipeline the job language cannot express. It is shell because
+94
;; there is nowhere else to put it.
+95
(shell "files=$(sed -n 's/^[[:space:]]*Files:[[:space:]]*\\([0-9][0-9]*\\) of .*/\\1/p' kiln-test.out | head -1)
+96
tests=$(sed -n 's/^[[:space:]]*Tests:[[:space:]]*\\([0-9][0-9]*\\) passed.*/\\1/p' kiln-test.out | head -1)
+97
for v in \"$files\" \"$tests\"; do
+98
case \"$v\" in '' | *[!0-9]*) echo \"SETUP-FAILED: floor could not read a count from kiln-test.out\"; exit 2 ;; esac
+99
done
+100
echo \"floor: files=$files (min 1), tests=$tests (min 33)\"
+101
[ \"$files\" -ge 1 ] || { echo \"FLOOR BREACHED: $files test files ran, expected at least 1\"; exit 1; }
+102
[ \"$tests\" -ge 33 ] || { echo \"FLOOR BREACHED: $tests tests ran, expected at least 33\"; exit 1; }
+103
echo 'floor: ok'"
+104
name: floor)
+105
+106
;; Staged last on purpose, and note what that costs: steps run under
+107
;; `set -e` and there is no post/always construct, so this does NOT
+108
;; run when an earlier step fails -- exactly the run whose output
+109
;; you would most want kept.
+110
(artifact "kiln-test.out" as: "test-output.txt")
+111
]))