The largest of these branches, because this repository had no Makefile, no
lockfile, no security workflow, and no SECURITY.md, CONTRIBUTING.md,
CODEOWNERS, or ADR log. Twenty-one automated checks were failing; nineteen of
them now pass, and the two that do not are named at the bottom rather than
worked around.
Nothing here changes what Cairn answers, how it retrieves, or how it is graded.
Thirteen uses: in ci.yml referenced a moving major tag. Each is now pinned
to a full commit SHA with a version comment, matching what pages.yml already
did.
The SHAs are the exact commits those major tags resolve to today
(actions/checkout v4.4.0, setup-python v5.6.0, setup-node v4.4.0, cache
v4.3.0, upload-artifact v4.6.2), so nothing about what runs has changed. What
has changed is that a moved tag can no longer change it. .github/dependabot.yml
is added in the same breath, because a pin with nothing raising it is a frozen
dependency rather than a careful one.
make verify runs the lockfile check, ruff, mypy, and the suite under coverage
with an 85 percent branch floor. Measured coverage is 89 percent, so the floor
sits below what the tree does, with room for a refactor and not for a
regression.
It is deliberately not a wrapper around ./plumbline-gate.sh. The merge
gate stays a separate, fail-closed job that resolves an external auditor over
the network, and folding it into make verify would invite "verify passed" to
be read as "the gate passed". The Makefile header and CONTRIBUTING.md both
say which is which.
uv.lock and .python-version come with it, so the development toolchain is a
reviewable resolution rather than whatever pip picked that morning. The runtime
is still standard library only and still has nothing to lock, and make demo
runs the no-install path the README opens with, so that claim keeps being
exercised.
.github/workflows/security.yml adds gitleaks over the full history, Semgrep,
and pip-audit over the development toolchain. All three run on push, on pull
request, and weekly. None can be skipped into a green check, and none has a
continue-on-error, for the reason ci.yml already argues at length about its
audit job.
They are kept out of ci.yml on purpose: the core job's argument is that it
needs nothing from outside this repository, and a scanner that has to be
fetched would undercut it.
SECURITY.md names three vulnerability classes specific to what this project
claims, rather than reciting a generic list: an answer no source supports, a
refusal that leaks what the corpus contains, and any path that makes the merge
gate report green without grading. CONTRIBUTING.md explains the two gates and
which one is which. docs/adr/0000-record-architecture-decisions.md starts the
log and says explicitly that it is not being backfilled, because records dated
today for decisions made months ago are the same dishonesty in a different
file. .github/CODEOWNERS and .pre-commit-config.yaml are one-liners.
tests/test_cli.py requires the first ## heading in CHANGELOG.md to be the
current version, because a changelog whose newest version section describes a
release that does not exist is worse than one that is behind. An ## Unreleased
heading breaks that test.
So unreleased work sits under ### Unreleased, one level down, and the file's
preamble now says why and says that it becomes a version section when the
version is bumped. That keeps the repository's own test and records the work,
rather than picking one.
Both are in the README's new conformance table and in the configuration comment at the point where each is set:
- mypy runs in its default mode, not
--strict. Strict reports 28 findings on this tree. Fixing them is a typing pass, not a settings change. - The complexity limit of 10 is configured, and the
C90rule is not switched on. Four functions are over it:audit_guard.py'ssuite_defaultsat 12,regression_findingsat 11 andrender_terminalat 11, andcairn/server.py'sbuild_handlerat 26. Turning the rule on is a refactor. The alternative was four silent per-file ignores, which is the manoeuvre the rest of this repository exists to make impossible.
requires-pythonstays at>=3.11. Raising it to 3.12 would drop a versionci.ymlcurrently tests in its matrix. That is a support decision.- No hardened release workflow. Tagging remains a manual act by the
maintainer, as
CHANGELOG.mddescribes. - No
docs/I18N.md. Three languages ship, one of them right to left. What is committed to beyond those three is a scope decision, so the README row records the absence rather than inventing an answer. ci.ymldoes not call the Makefile targets. Itscorejob still runspip install -e ".[dev]",ruff check ., and the unittest discovery directly. Rewiring it tomake verifywould remove a real drift risk, but it would also introduceuvinto a job whose whole argument is minimal dependencies, and it is not something this change could exercise. Left as follow-up.
make verify exits 0: 358 tests, one skip, 89 percent branch coverage against
the 85 percent floor, ruff clean, mypy clean. The site staleness check and the
docs tests, which execute every command block in README.md and
docs/demo.md, both pass with the new README section in place.