Commit8b4bfdeaRecorded1 Sep 2026Repositorykiln

Gate the artifacts and the checks ledger, not just the logs

Message

The brief's gate names "logs, artifacts and checks ledger" and the clickthrough arm asserted only the first. render-artifacts returns the empty string for a run with no artifacts, so a fixture that produced none left the artifact path unreachable and any assertion about it vacuous.

The fixture pipeline now writes a ledger into $KILN_ARTIFACTS with no artifact step, which is what .kiln/ci.sh does: the runner sets that variable to <workspace>/artifacts on both the legacy and the node paths and retrieve-artifacts! copies the directory back regardless.

The arm now scrapes the artifact href off the rendered run page, fetches it, and requires the downloaded bytes to be the ledger the run wrote -- so a rendered panel whose links do not resolve reddens too.

Changed
 test/integration/test-run-addressing.sh | 27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)
Diff
test/integration/test-run-addressing.shmodified
@@ -186,10 +186,19 @@ $2
186
EOF
187
}
188
+189
# THE FIXTURE WRITES A CHECK LEDGER, because the gate this work was given names
+190
# "logs, artifacts and checks ledger" and an artifacts panel renders NOTHING
+191
# when a run produced no artifacts -- so a run with none would let the artifact
+192
# assertions pass vacuously by never being reachable.
+193
#
+194
# It writes straight into $KILN_ARTIFACTS with no `artifact` step, which is what
+195
# .kiln/ci.sh does: the runner sets KILN_ARTIFACTS to <workspace>/artifacts on
+196
# both the legacy and the node paths, and retrieve-artifacts! copies that whole
+197
# directory back regardless of any `artifact` step.
198
mk_pipeline ci.sgv '(pipeline ci
199
on: #[ (manual) ]
200
(job ci
−192
steps: #[ (shell "echo addressing-gate-node-ran" name: checks) ]))'
+201
steps: #[ (shell "echo addressing-gate-node-ran; mkdir -p \"$KILN_ARTIFACTS\"; printf %s\\n \"check: addressing-gate PASS\" > \"$KILN_ARTIFACTS/checks.ledger\"" name: checks) ]))'
202
203
register() { # slug anchor-job-name
204
k job add "$2" --repo "$1" > "$G/.add.$2" 2>&1 || true
@@ -337,7 +346,21 @@ if wants clickthrough; then
346
|| fail "the run page does not link back to its group; navigation only works downward"
347
echo "$PAGE" | grep -q 'log-viewer' \
348
|| fail "the run page rendered no log viewer"
−340
ok "the group page's own link resolves to a page carrying the run's logs, its repo, and a link back to the group"
+349
# ARTIFACTS AND THE CHECKS LEDGER, which are the other two things the gate
+350
# for this work names. The artifacts panel renders the empty string when a
+351
# run produced nothing, so asserting its ABSENCE would pass for free -- the
+352
# fixture writes a real ledger into $KILN_ARTIFACTS so there is something
+353
# for the panel to be wrong about.
+354
echo "$PAGE" | grep -q 'checks.ledger' \
+355
|| fail "the run page does not list the run's checks ledger. Logs, artifacts and the ledger are the three things an operator opens a run page for, and before this change all three were reachable only through the JSON API."
+356
ALINK=$(echo "$PAGE" | grep -o 'href="/artifacts/[^"]*"' | head -1 | sed 's/href="//; s/"$//')
+357
[ -n "$ALINK" ] || fail "the run page rendered no artifact link"
+358
say "run page emits artifact href=$ALINK"
+359
[ "$(code "$ALINK")" = 200 ] \
+360
|| fail "the artifact link on the run page answered $(code "$ALINK"). A rendered panel whose links do not resolve is the same defect one layer down."
+361
pub "$ALINK" | grep -q 'addressing-gate PASS' \
+362
|| fail "the artifact downloaded through the run page's own link is not the ledger the run wrote"
+363
ok "the group page's own link resolves to a page carrying the run's logs, its checks ledger as a downloadable artifact, its repo name, and a link back to its group"
364
fi
365
366
# ==================================================================