Commit2e152991Recorded1 Sep 2026Repositorysigil-http

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