Skip to content

No justfile and no AGENTS.md: the org's pre-commit gate cannot be run here #28

Closed

Description

@CameronBrooks11

gerberdiff is the only code member of this org with neither a justfile nor an AGENTS.md.

Measured

$ for r in partspec netspec slicelab orlab prusaslicer-py gerberdiff; do
    printf '%-16s justfile=%s AGENTS.md=%s\n' "$r" \
      "$([ -f $r/justfile ] && echo y || echo n)" \
      "$([ -f $r/AGENTS.md ] && echo y || echo n)"; done
partspec         justfile=y AGENTS.md=y
netspec          justfile=y AGENTS.md=y
slicelab         justfile=y AGENTS.md=y
orlab            justfile=y AGENTS.md=y
prusaslicer-py   justfile=y AGENTS.md=y
gerberdiff       justfile=n AGENTS.md=n

grep -rn 'just ' CONTRIBUTING.md README.md docs/*.md .github/workflows/*.yml returns
one hit, and it is the English word inside a comment in docs.yml.

Why it matters

Org contract section 8 makes just check && just test the pre-commit gate for every
member. Here neither command exists, so the gate cannot be run at all -- not skipped,
not weakened, absent. What a contributor runs instead is the four commands in
CONTRIBUTING.md, typed by hand:

uv run ruff check gerberdiff/ tests/
uv run ruff format gerberdiff/ tests/
uv run mypy gerberdiff/ tests/
uv run pytest tests/ -q

Three gaps between that list and what ci.yml actually enforces:

  • ruff format (mutating) versus CI's ruff format --check. Running the documented
    command makes the working tree pass; it does not tell you whether it would have
    failed.
  • No coverage gate. CI runs pytest --cov=gerberdiff --cov-fail-under=90; the
    documented command runs pytest tests/ -q. A change that drops coverage below 90
    passes locally and fails in CI.
  • No ASCII check. CI has a grep -rP '[^\x00-\x7F]' gerberdiff/ tests/ *.md *.toml
    step, and CONTRIBUTING.md documents the rule with a 12-row table of banned
    characters and a here-doc Python script to check it. Nothing runs that script; the
    only enforcement is the CI step, i.e. after the push.

So "ran the documented checks locally" and "will pass CI" are different claims in this
repo, and the difference is silent in the direction that reads as success.

And there is no AGENTS.md

The exit-code contract this repo settled in 0685cde (A3) -- 0 identical, 1
different, 2 indeterminate, 4 environment fault, 64 usage, with 2 spelled as a
third diff outcome rather than a verdict -- is currently recorded only in a
docstring in gerberdiff/cli.py, in DiffOutcome in gerberdiff/geometry/types.py,
and in docs/schema.md. There is no repo-level file telling an agent that this is
settled and not to relitigate it. Nor that planning/ is gitignored working material
rather than a plan, that docs/DECISIONS.md does not exist here, or that
geomdiff can return 2 and the raster diff cannot.

Done when

  • a justfile exists whose check recipe runs the same four things ci.yml
    runs (lint, format-check, ASCII, typecheck) and whose test recipe carries the
    --cov-fail-under=90 gate, so just check && just test is CI-equivalent rather
    than a shorter list with the same name
  • an AGENTS.md exists naming the org contract as the floor and carrying what is
    specific to gerberdiff
  • CONTRIBUTING.md points at the recipes instead of listing commands that drift
    from CI

Deriving the recipes from ci.yml rather than copying a sibling's justfile is the
point: partspec and netspec typecheck with pyright, this repo uses mypy, and no
sibling has the ASCII step.

Activity

  1. CameronBrooks11 commented on Sep 10, 2026

    @CameronBrooks11
    MemberAuthor

    Fourth item for this issue: the ASCII step checks a fifth of the tree

    Found while writing the ascii recipe in #29. Pre-existing in ci.yml, not introduced there.

    CONTRIBUTING.md states the rule for all tracked files: "All tracked files must be pure ASCII (U+0000--U+007F). This covers Python source, tests, TOML, YAML, Markdown, and any other text file in the repo." The step's argv is gerberdiff/ tests/ *.md *.toml, and the last two are root-level globs, so nothing in a subdirectory that is not gerberdiff/ or tests/ is read.

    Measured

    26 of 131 tracked files are text the check never opens:

    .editorconfig
    .github/ISSUE_TEMPLATE/bug_report.yml
    .github/ISSUE_TEMPLATE/config.yml
    .github/ISSUE_TEMPLATE/feature_request.yml
    .github/PULL_REQUEST_TEMPLATE.md
    .github/dependabot.yml
    .github/workflows/ci.yml
    .github/workflows/docs.yml
    .github/workflows/release.yml
    .gitignore
    .pre-commit-config.yaml
    LICENSE
    docs/api.md
    docs/architecture.md
    docs/changelog.md
    docs/cli.md
    docs/contributing.md
    docs/geometry-diff.md
    docs/index.md
    docs/javascripts/mathjax.js
    docs/reference/geometry.md
    docs/reference/package.md
    docs/schema.md
    justfile
    mkdocs.yml
    uv.lock
    

    docs/ is the whole published documentation site. justfile is the file that carries the recipe enforcing the rule, and it is outside the rule.

    The fix is one argv, but it needs a decision first

    git ls-files -z | xargs -0 grep -lP ... covers everything and needs no glob list to maintain. Two things to settle before running it:

    • uv.lock and LICENSE. Both are generated or vendored, neither is hand-edited, and a non-ASCII byte in either is not a contributor mistake to reject. Exclude them explicitly, or accept that a dependency with a non-ASCII author name breaks CI.
    • What the rule is actually for. CONTRIBUTING.md argues from terminals, diff tools and grep. That argument is strongest for source and weakest for docs/, which renders as UTF-8 HTML on a docs site. Widening to docs/ is a real constraint on documentation prose, so it should be chosen rather than inherited from a glob.

    Whichever way it goes, verify by planting the character in a file from each newly-covered directory and watching it fail -- the current glob passes on inputs it was written to reject, which is what made this worth adding here.

    Also for the just ascii recipe

    grep -rP descends into __pycache__, whose .pyc bytes are not ASCII. CI never saw it because a clean checkout has no caches; running the same command locally after a test run does. #29 adds --exclude-dir=__pycache__ to both the workflow step and the recipe. A git ls-files-driven form makes that flag unnecessary, since untracked files are not listed.

    AGENTS.md in #29 records the gap as it stands, scoped to what the check reads, and points here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions