Files
zhanghui ae0e062fb4 ci: enforce the file-size ceiling on pull requests (#387)
* ci: enforce the file-size ceiling on pull requests

`check-added-large-files` only ran in pre-commit, so the ceiling was absent
from CI: an unhooked clone or `--no-verify` bypassed it entirely, and the
hook is weaker than it looks even locally — it inspects only files being
*added*, so an existing fixture that grows never trips it.

Add `scripts/check_file_sizes.py`, wired into `make lint` and therefore the
required `lint` check. It diffs against the base branch's merge base and
measures additions, modifications and renames, leaving files already
committed above the ceiling alone so no pull request fails for something it
did not touch. An unresolvable base is a hard failure rather than a silent
pass. The `lint` job now checks out with `fetch-depth: 0` to provide it.

Lower the hook's `--maxkb` from 1024 to 640 to match, and pin the two limits
equal in a unit test so they cannot drift back apart.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* ci: catch untracked oversized files in the size gate

`git diff` cannot see a newly created file until it is staged, so a local
`make check-file-sizes` passed a brand-new 700 KB file — verified against the
real script, not reasoned about. CI was unaffected (its checkout has
everything committed), but the docstring claimed the local run covered
uncommitted work, which was only true for edits to already-tracked files.

Union in `git ls-files --others --exclude-standard`, which respects
.gitignore, and pin both the untracked and the ignored case in tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* ci: exempt the generated search-seed corpora from the size ceiling

tests/fixtures/search_seed/ holds embedded corpora regenerated by
_dump_search_seed.py. Two of them are already near 1 MB and grew ~60% in one
release, so the next refresh would have hit the 640 KB ceiling and the
cheapest fix would have been raising it for the whole repository — a gate that
teaches people to edit the gate.

Exempt that one directory by path prefix instead. Outside it the largest
tracked file is ~300 KB, so 640 KB still binds where it matters, including the
examples/ case that prompted this work. Three tests pin the carve-out: a
sibling of the exempt directory is still caught, the list itself is asserted
verbatim so growth shows up in review, and every prefix must name a directory
that actually exists.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: zhanghui <zhanghui@shanda.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 07:57:09 +08:00

6.3 KiB

Engineering Reference

Companion docs: system design lives in architecture.md; coding rules live in ../.claude/rules/. This document is the contributor-facing reference for building, testing, and shipping a change — the toolchain, the CI gates, and the branch / commit conventions your pull request must satisfy.

Toolchain

Tool Role
uv sole package manager (uv sync; do not use pip install)
hatchling wheel build backend (src layout under src/everos)
ruff lint + format (replaces black / isort / flake8)
import-linter enforces the DDD layer dependency direction
pytest unit + integration tests
pre-commit local gate run before each commit
Makefile single entry point for every command — CI invokes the same targets

All tool configuration lives in a single pyproject.toml (ruff, pytest, coverage, and the import-linter layer contracts) — there are no separate pylintrc / pytest.ini / .isort.cfg files.

Local development

make install      # uv sync --frozen
make format       # ruff fix + format
make lint         # ruff check + format-check + import-linter + datetime/asset/name guards
make test         # pytest tests/unit
make integration  # pytest tests/integration
make cov          # unit + integration with coverage (gate: 80%)
make ci           # lint + test + integration  — run this before pushing
make help         # list every target

CI runs the same make targets, so a green make ci locally predicts a green pipeline.

Configuration

Settings load in ascending priority:

  1. src/everos/config/default.toml — shipped with the package (lowest)
  2. <memory-root>/everos.toml — user config (optional)
  3. EVEROS_* environment variables (highest)

Run everos init to generate starter config and everos config show to inspect the effective result. Full reference: configuration.md.

Quality gates

Each stage can independently fail a change; there is no --no-verify bypass.

1. Editor      ruff (lint + format) on save
2. pre-commit  ruff, trailing-whitespace / EOF, yaml & toml checks,
               file-size & private-key guards, merge-conflict check,
               and gitlint (commit-msg stage) — see "Commits" below
3. make ci     lint + unit + integration — run before pushing
4. GitHub CI   re-runs the same make targets on every pull request
5. Review      1 approval + all conversations resolved + all checks green

Stage 2 runs only on machines that ran make install, so CI cannot rely on it. Where a pre-commit guard must hold for every pull request it has a make counterpart re-run by CI.

File-size ceiling — 640 KB. Enforced locally by check-added-large-files and on every pull request by scripts/check_file_sizes.py (make check-file-sizes, wired into make lint). The two limits are pinned equal by a unit test; change them in the same commit. The CI gate is the stronger of the two in scope: the local hook only inspects files being added, so it cannot catch an existing file that grows, while the gate diffs against the base branch and covers additions, modifications and renames alike. Files already committed above the ceiling are out of scope — the gate never fails a pull request for something it did not touch. Because it needs a merge base, the lint job checks out with fetch-depth: 0.

One directory is exempt: tests/fixtures/search_seed/, whose search corpora are regenerated by tests/fixtures/_dump_search_seed.py and already approach 1 MB. Outside it the largest tracked file is ~300 KB, so the ceiling stays meaningful. Prefer adding a directory to EXEMPT_PREFIXES over raising MAX_KB for the whole repository; a unit test pins the list so it cannot grow unnoticed.

Continuous integration

CI runs on GitHub Actions (.github/workflows/). Every pull request into main must pass:

Check Command Guards
lint make lint ruff style, DDD layer direction (import-linter), datetime discipline, asset, file-size & deprecated-name guards
unit tests make test tests/unit
integration tests make integration tests/integration
package build make package the wheel builds and imports cleanly
docs make docs-check Markdown and internal-link validity
commit messages / PR title make check-commits / make check-pr-title Conventional Commits format

main is a protected branch: no direct pushes; changes land through a reviewed pull request with all checks green.

Contributing workflow

  • Branch off main, then open a pull request back into main.
  • Commits and the PR title follow Conventional Commits: type(scope): subject, with the subject ≤ 72 characters and no leading emoji. Allowed types: feat, fix, refactor, test, docs, style, perf, chore, build, ci, revert. This is enforced both locally (gitlint, commit-msg stage) and in CI.
  • Pull requests use .github/PULL_REQUEST_TEMPLATE.md (changes / scope / API impact / tests / checklist).
  • Issues use the templates under .github/ISSUE_TEMPLATE/.

See CONTRIBUTING.md for the full onboarding walkthrough.

This repository also ships Claude Code configuration — coding rules under .claude/rules/ and slash-command workflows under .claude/skills/ — that encode the conventions above. It is optional convenience tooling: using Claude Code is not required to contribute, and the CI gates remain the source of truth.

References