Skip to content

docs: второй край предиката — обнаружение тоже продукт #92

docs: второй край предиката — обнаружение тоже продукт

docs: второй край предиката — обнаружение тоже продукт #92

Workflow file for this run

name: gates
# The first CI this repository has had. Until now every check on a pure-markdown plugin
# was a thing someone remembered to run, which is why a version could sit wrong in two
# READMEs through a release and a section could advertise 97 catalog entries against 92.
#
# Runs on ubuntu-latest deliberately, not macOS: the tools are written against BSD
# behaviour on the author's machine, and a Linux runner is the second opinion that catches
# a GNU/BSD divergence before a contributor does. The tools set LC_ALL=C for the same
# reason they set it locally — the corpus is Russian, and locale-dependent string handling
# has already silently mis-parsed it once.
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
concurrency:
group: gates-${{ github.ref }}
cancel-in-progress: true
jobs:
gates:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Tools are executable and POSIX-parseable
# A syntax error in a checker reads as a passing checker to anything that only
# looks at whether the file exists.
# `find`, not the `tools/*.sh` glob: the glob stops at the top level, and a checker
# one directory down was invisible here and to tools/gates.sh both. Kept identical
# to the loop in tools/gates.sh — tools/selftest.sh fails when the two diverge.
run: |
set -eu
for f in $(find tools -name '*.sh' -type f | sort); do
[ -x "$f" ] || { echo "not executable: $f"; exit 1; }
sh -n "$f" || { echo "syntax error: $f"; exit 1; }
done
- name: Python tools are executable and parseable
# Mirrors the .py loop in tools/gates.sh — tools/ gained its first Python file
# and the shell loop cannot see it.
run: |
for f in $(find tools -name '*.py' -type f | sort); do
test -x "$f" || { echo "not executable: $f"; exit 1; }
python3 -c "import ast,io,sys; ast.parse(io.open(sys.argv[1],encoding='utf-8').read(), sys.argv[1])" "$f"
done
- name: Selftest — every checker must be able to fail
# Runs first. If the checkers cannot fail, their passing below means nothing.
run: tools/selftest.sh
- name: check-frozen — the paid-MCP corpus contract
run: tools/check-frozen.sh
- name: check-version — one version, one description budget, one set of triggers
# The description is the entire trigger on hosts that have no instruction file.
# Losing a Russian phrase there stops the skill firing for the people it is for,
# silently, with every other gate still green.
run: tools/check-version.sh
- name: check-dogfood — the numbers the product states about itself
# The catalogue size lives in seven files. Four of them went stale unnoticed
# the last time it moved, which is why the completeness guard exists.
run: tools/check-dogfood.sh
- name: check-typography — the product obeys its own typography
# The README claims every dash, quote and space in it follows the plugin's own
# rules. Until this step that claim rested on someone remembering to ask a model,
# and in one afternoon a literal ~ and a missing non-breaking space both shipped.
run: tools/check-typography.sh
- name: selftest-check-private — the boundary gate proves it can red
# Nine cases, including the control that the mere SUBJECT of the paid service stays
# allowed. Without this step the gate's own claim rested on someone having run it
# once by hand — the promise-without-a-mechanism this whole change set is against.
run: tools/selftest-check-private.sh
- name: check-private — no identifier of the private contour in tracked files
# Guards an irreversible event rather than a fixable one: a hostname, a repo name
# or a token in a public commit cannot be recalled from the release tags or from
# any clone. The deny-list holds identifiers only — this repository legitimately
# discusses the paid service, and a gate that reds on the subject would be off
# within a week.
run: tools/check-private.sh
- name: check-assets — manifest images exist, are square, and fit the limit
run: tools/check-assets.sh
- name: No-loss gate — every atom of the pinned baseline still accounted for
# The baseline is the v1.10.1 corpus, frozen as a historical artefact: it is NOT
# regenerated when the corpus changes. That is the whole point — it is the "before"
# side of every comparison from here to the v2.0 release. A rule that leaves the
# corpus must appear in tools/atom-map.tsv with what happened to it, or this fails.
run: |
set -eu
# The baseline is pinned by content, not by policy. Without this, deleting a
# rule from the corpus AND its line from the baseline passes every gate green:
# the comparison is with a file the same commit is free to edit. Changing the
# pin is then a visible line in a diff rather than a quiet edit inside a
# 1825-line data file. It moves once, at the v2.0 release.
sha256sum -c - <<'PIN'
98b2e03bc771d7c0b3268f4eb406fbb3641bc8fdb01243ff3053a1790e2b3aa4 tools/baseline/atoms-v1.10.1.tsv
PIN
tools/extract-atoms.sh skills/ru-text > /tmp/atoms-now.tsv
tools/diff-atoms.sh tools/baseline/atoms-v1.10.1.tsv /tmp/atoms-now.tsv
- name: The release assets can still be built
# Writes nothing. A renamed reference file leaves the skill installing and
# answering from whatever it still has — a failure with no symptom.
run: tools/build-release.sh --check