Files
FabledScribe/ci-requirements.md
T
bvandeusenandClaude Opus 5 7e653e16dc docs(ci): jq is not a CI requirement and should not be promoted (#4107)
ci-requirements.md is the document that drives promoting a per-job dep into
the ci-python image, and it still recorded jq as installed in the plugin job
and "load-bearing for the smoke test specifically", on the grounds that every
hook opened `command -v jq || exit 0` and the test would otherwise pass while
exercising nothing.

That was the tail wagging the dog. The hooks ship to users; jq is absent by
default on macOS, the Debian/Ubuntu slim images, Alpine and most CI
containers, and a machine without it got no context, no rules, no prior art
and no process sync in silence. The answer was to remove the dependency, not
to install it harder.

Recorded as a promotion the entry now argues AGAINST rather than deleted: the
next person to read this file should find out why jq is absent, not merely
that it is.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
2026-09-20 12:24:37 -04:00

2.8 KiB

CI Requirements — FabledScribe

Spec lives in docs/process.md in the CI-Runner repo.

Runtime image

git.fabledsword.com/bvandeusen/ci-python:3.14

Used by all six jobs in .forgejo/workflows/ci.yml: typecheck (Vue/TS), plugin (hook checks), lint (ruff), test (pytest), integration (pytest + real Postgres), build (docker buildx).

Image deps used

  • python 3.14
  • node 24 (used for npm ci + vue-tsc in the typecheck job, and as the frontend builder stage inside the production Dockerfile)
  • ruff (lint job runs ruff check src/ with zero install overhead)
  • uv (test + integration jobs run uv sync --locked; installed in the image since the ci-python Dockerfile started pip-installing it)
  • docker CLI + buildx (build job pushes the production image to the Fabled-Git registry)

Per-job tool installs

Anything CI installs at job time that isn't in the image. Promotion candidates if more than one project needs them.

  • shellcheck — apt-installed in the plugin job, which lints the Claude Code hook scripts and runs their fail-open smoke test. Per docs/process.md's decision checkpoint, single-consumer deps stay per-job until a second consumer wants them; Scribe is the only one so far. It is small (~20 MB) and would be a promotion candidate the moment another project lints shell.

  • jqno longer installed anywhere, and should not be promoted. It was installed in two jobs, and this file used to record it as "load- bearing for the smoke test specifically", because every hook opened command -v jq || exit 0 and the test would otherwise pass while exercising nothing. That was the tail wagging the dog: the hooks ship to users, jq is absent by default on macOS, the Debian/Ubuntu slim images, Alpine and most CI containers, and a machine without it got no context, no rules, no prior art and no process sync in silence. #4107 removed the dependency rather than documenting it, so the smoke test now runs on a bare image — which is the condition it was always meant to assert. The hooks use only POSIX tools (awk, sed, tr, od, cut, head, tail, grep, sort, date, printf) plus git and curl.

Notes

  • Production runtime image (Dockerfile) also tracks Python 3.14 — the CI image and runtime image stay aligned by design so test results are representative.
  • Build wall time: dominated by pytest (full async test suite). Cold ci-python pulls add ~30s; not a blocker.
  • Registry-backed BuildKit layer cache (type=registry,ref=…:cache,mode=max) gives ~80% speedup on warm builds — see the build job comment.
  • pyproject.toml pins requires-python = ">=3.14" to match the CI + runtime target; lockfile (uv.lock) is committed and resolves against Python 3.14.