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
]))