Chemenu 2.1.0 - deterministischer Wissenskompiler
Chemenu kompiliert Rohnotizen zu einem verlinkten, quellengebundenen Wiki: raw/ -> types/ + tools/ -> kb/ -> reports/. Was mechanisch ist, macht tools/wikitool; was Urteil braucht, macht ein Agent unter Contracts, deren Grenzen in Code durchgesetzt sind statt im Prompt. Dieser Commit ist der Startpunkt der oeffentlichen Historie. Die vorherige Entwicklung fand in einer privaten Instanz statt und ist nicht Teil dieses Repositorys; ihre Erzaehlung steht vollstaendig in CHANGES.md, das mit 44 Eintraegen von 0.1.0 bis 2.1.0 erhalten geblieben ist. Der mitgelieferte Korpus ist ein Testbett und eine Demo: 170 Seiten ueber den Stack selbst - Gates, Lint, Versionierung, Suche, das Wiki-Muster. Er dokumentiert das Werkzeug mit den eigenen Mitteln des Werkzeugs. Lizenz: AGPL-3.0 fuer den Stack (tools/, types/), CC-BY-4.0 fuer die Inhalte. Die Grenze zwischen beiden ist der Dateiplan, den dist export berechnet - siehe NOTICE.
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
# CI for the wiki stack.
|
||||
#
|
||||
# One job, stopping at the first failure - the stack has no artifact to build
|
||||
# and nothing to deploy, so the pipeline's whole job is "does the machinery
|
||||
# still hold together, and does the distribution it produces still work".
|
||||
#
|
||||
# Runner: `linux-docker` is one of this Gitea instance's three routing labels
|
||||
# (alongside `container-builder` and `k3s-deploy`). The job image is named
|
||||
# explicitly rather than inherited from the runner's label mapping, which is
|
||||
# not documented anywhere: `debian:trixie-slim` is the base the instance's
|
||||
# container-build workflows already use, and Trixie's python3 is 3.13, past
|
||||
# the 3.11 floor `doctor` enforces.
|
||||
#
|
||||
# Pinning that image makes `nodejs` this workflow's own responsibility.
|
||||
# `actions/checkout` is a JavaScript action, and act_runner runs it with `node`
|
||||
# *inside the job container* - a slim Debian has none, and the job dies with
|
||||
# exit 127 before any step of ours runs. The shape below (apt `nodejs` first,
|
||||
# then `checkout@v7`) is the one proven on this instance by
|
||||
# torben/gitea-mcp@ci-build, workflow `ci-build.yaml`, runs 42-45.
|
||||
#
|
||||
# Triggers: content commits are excluded. `publish` touches kb/, raw/ and work/
|
||||
# and never the stack, so running the suite for them would be pure noise. The
|
||||
# exclusions are deliberately literal rather than a `!**/CONTRACT.md` negation,
|
||||
# whose support in Gitea's filter matching is unverified: every pattern here
|
||||
# names content, so anything unanticipated still triggers CI. The list is
|
||||
# repeated rather than shared through a YAML anchor for the same reason -
|
||||
# GitHub's parser rejects anchors outright, and Gitea's is not documented to
|
||||
# accept them. `kb/CONTRACT.md` is absent on purpose: it is a stack file that
|
||||
# happens to live under a content directory, and it must keep its CI.
|
||||
#
|
||||
# That the filter works is now observed, not assumed (Gitea issue #11): commit
|
||||
# f916376 published only kb/ and raw/ paths and produced no run at all, while
|
||||
# the stack commits on either side of it (adfa220, 40adbb7) each produced two.
|
||||
# Gitea evaluates these patterns the way GitHub does. Do not re-derive this.
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- 'kb/*/**'
|
||||
- 'kb/index.md'
|
||||
- 'kb/log.md'
|
||||
- 'kb/provenance.md'
|
||||
- 'raw/*/**'
|
||||
- 'work/*/**'
|
||||
- 'reports/*/**'
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- 'kb/*/**'
|
||||
- 'kb/index.md'
|
||||
- 'kb/log.md'
|
||||
- 'kb/provenance.md'
|
||||
- 'raw/*/**'
|
||||
- 'work/*/**'
|
||||
- 'reports/*/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
runs-on: linux-docker
|
||||
container:
|
||||
image: debian:trixie-slim
|
||||
env:
|
||||
# Scope the Iteration Budget Gate to this run instead of letting it fall
|
||||
# back to the parent PID, and keep the trace out of the checkout so the
|
||||
# working tree stays clean for the ignore-rule checks.
|
||||
WIKITOOL_SESSION_ID: ci-${{ github.run_id }}
|
||||
WIKI_TRACE_DIR: /tmp/wikitool-trace
|
||||
DIST_DIR: /tmp/dist
|
||||
|
||||
steps:
|
||||
- name: System dependencies
|
||||
# `nodejs` is not for us - it is what act_runner needs to execute the
|
||||
# JavaScript action in the next step. It has to be installed before the
|
||||
# checkout, which is why this step comes first.
|
||||
run: |
|
||||
set -eu
|
||||
apt-get update -qq
|
||||
apt-get install -y --no-install-recommends \
|
||||
python3 python3-venv git nodejs ripgrep ca-certificates
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
# The version gate diffs against the pushed range's base, so the
|
||||
# shallow default clone is not enough.
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Tool environment
|
||||
run: |
|
||||
set -eu
|
||||
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
python3 -m venv tools/.venv
|
||||
tools/.venv/bin/pip install --quiet --upgrade pip
|
||||
tools/.venv/bin/pip install --quiet -r tools/requirements.txt
|
||||
# pytest-cov is CI-only: tools/requirements.txt describes what an
|
||||
# *instance* needs at runtime and ships with `dist export`, and an
|
||||
# instance does not measure this suite. Installed beside pytest for
|
||||
# the same reason pytest itself is.
|
||||
tools/.venv/bin/pip install --quiet pytest pytest-cov
|
||||
|
||||
- name: Tests
|
||||
# Not run with WIKI_TRACE=0: two telemetry tests assert that a trace is
|
||||
# written, and disabling the emitter globally fails them. The suite
|
||||
# redirects WIKI_TRACE_DIR per test on its own.
|
||||
#
|
||||
# One run, not two. This job used to be the only place the suite met a
|
||||
# machine with no global git configuration, which is how Gitea #8 was
|
||||
# found - two tests that silently read the developer's `git config
|
||||
# user.name`. That hole is now closed in the suite itself: the autouse
|
||||
# `hermetic_environment` fixture gives every test an empty HOME, no
|
||||
# git configuration and none of the tool's own environment, so this
|
||||
# container is no longer a special environment worth a second run.
|
||||
# See instructions/dev/testing-conventions.md.
|
||||
#
|
||||
# Coverage is reported, not enforced: there is deliberately no
|
||||
# `--cov-fail-under` yet (Gitea #10). The threshold gets set in its own
|
||||
# later commit, with the measured number as its justification - one
|
||||
# picked before the number is either too low to bite or too high to
|
||||
# survive the next honest commit, and the second kind gets lowered
|
||||
# instead of earned. Config: tools/.coveragerc.
|
||||
run: |
|
||||
set -eu
|
||||
cd tools
|
||||
.venv/bin/python -m pytest -q \
|
||||
--cov --cov-report=term --cov-report=xml --cov-report=html
|
||||
|
||||
- name: Coverage report
|
||||
# `always()`: a red suite is exactly when the per-module numbers are
|
||||
# worth reading, and the upload must not disappear with the failure.
|
||||
# v3, not v4 - v4 is restricted on this Gitea instance; v3 is what is
|
||||
# proven here (torben/gitea-mcp@ci-build, ci-build.yaml, runs
|
||||
# 42-45).
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: coverage-${{ github.run_id }}
|
||||
path: |
|
||||
tools/coverage.xml
|
||||
tools/htmlcov/
|
||||
retention-days: 14
|
||||
|
||||
- name: Verify the development tree
|
||||
run: |
|
||||
set -eu
|
||||
tools/wikitool docs verify
|
||||
tools/wikitool instructions verify
|
||||
tools/wikitool lint --fail-on-error
|
||||
|
||||
- name: Version gate
|
||||
# A stack change with no version bump cannot be released, because the
|
||||
# release would carry a change nobody named. Scoped to what
|
||||
# `dist export` actually ships as behaviour - prose docs and these
|
||||
# workflows are not in it, and a typo fix should not force a bump.
|
||||
env:
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
BEFORE_SHA: ${{ github.event.before }}
|
||||
run: |
|
||||
set -eu
|
||||
base="${BASE_SHA:-${BEFORE_SHA:-}}"
|
||||
case "$base" in
|
||||
""|0000000000000000000000000000000000000000)
|
||||
echo "No base commit to compare against - skipping the version gate."
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
if ! git cat-file -e "${base}^{commit}" 2>/dev/null; then
|
||||
echo "Base commit $base is not in this clone - skipping the version gate."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
changed="$(git diff --name-only "$base" HEAD)"
|
||||
stack="$(printf '%s\n' "$changed" \
|
||||
| grep -E '^(tools/|types/|instructions/|AGENTS\.md$|[^/]+/CONTRACT\.md$)' || true)"
|
||||
|
||||
if [ -z "$stack" ]; then
|
||||
echo "No stack paths touched - no version bump required."
|
||||
exit 0
|
||||
fi
|
||||
if printf '%s\n' "$changed" | grep -qx 'VERSION'; then
|
||||
echo "Stack changed, and VERSION moved to $(cat VERSION)."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Stack paths changed without a VERSION bump:"
|
||||
printf '%s\n' "$stack" | sed 's/^/ /'
|
||||
echo ""
|
||||
echo 'Fix: tools/wikitool version bump --patch --title "<what changed>"'
|
||||
echo 'Then `docs verify` holds VERSION and CHANGES.md together.'
|
||||
exit 1
|
||||
|
||||
- name: Export the distribution
|
||||
run: tools/wikitool dist export "$DIST_DIR"
|
||||
|
||||
- name: The distribution works as a fresh instance
|
||||
# Replays instructions/setup-instance.md end to end, minus its four
|
||||
# interactive decision points. What this tests is the release artifact
|
||||
# as an artifact: the documented path from an unpacked export to a
|
||||
# verified instance. Running one `instructions verify` against the
|
||||
# export would only have re-checked the file it just copied.
|
||||
#
|
||||
# Personalization is stubbed the same way the identity is: the real
|
||||
# step interviews the user, so CI substitutes a fixed answer - here,
|
||||
# the template minus its sentinel line. That is deliberately the
|
||||
# cheapest thing `doctor`'s personalization check accepts, because
|
||||
# what is under test is that the export *carries* the templates, not
|
||||
# what a person would write into them.
|
||||
run: |
|
||||
set -eu
|
||||
cd "$DIST_DIR"
|
||||
git init -q -b main
|
||||
git config user.name "CI Instance"
|
||||
git config user.email "ci@example.invalid"
|
||||
for personal in USER SOUL; do
|
||||
grep -v 'wikitool:template-unfilled' "$personal.md.template" > "$personal.md"
|
||||
done
|
||||
python3 -m venv tools/.venv
|
||||
tools/.venv/bin/pip install --quiet -r tools/requirements.txt
|
||||
tools/wikitool instructions sync
|
||||
tools/wikitool index rebuild
|
||||
tools/wikitool sources rebuild-index
|
||||
tools/wikitool doctor
|
||||
tools/wikitool docs verify
|
||||
tools/wikitool instructions verify
|
||||
tools/wikitool lint --fail-on-error
|
||||
tools/wikitool version show
|
||||
# A fresh instance owes no migration: dist export declares its content
|
||||
# version, so `status` must answer rather than ask for a baseline.
|
||||
tools/wikitool migrate status
|
||||
Reference in New Issue
Block a user