Files
prompts/prompts/EXISTING_REPO_CHECKLIST.md
sneak ae183d5529
All checks were successful
check / check (push) Successful in 23s
Gate the build on Docker lint and test phases (closes #40, closes #30)
Per the owner ruling on issue 40, linting and testing are phases of the
main Dockerfile rather than a separate lint file. script/lint and
script/test build one phase each by name with caching disabled, and the
final stage copies a harmless file from each so the image cannot be built
unless both passed — template-app-go's ordering trick, extended to the
test phase. A stage that is not the last is built only when something
depends on it or --target names it, so the gates are invoked by name and
the edges kept. script/check runs the gates and builds no image;
script/cibuild bootstraps first, because CI runs it alone and fmt-check
is native. Every build in script/ is tagged and uncached. No config
verify step. Issue 30 closes too: a container has its own lint cache and
lock.

Model: opus-5
2026-09-08 05:27:17 +00:00

8.6 KiB

title, last_modified
title last_modified
Existing Repo Checklist 2026-09-08

Use this checklist when beginning work in a repo that may not yet conform to our repository policies (https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md).

Work on a feature branch. Check each item and fix any gaps before proceeding with your task.

Formatting (do this first)

  • If the repo has never been formatted to our standards, run make fmt and commit the result as a standalone branch/commit/PR before any other changes. Formatting diffs can be large and should not be mixed with functional changes.

Required Files

  • README.md exists with all required sections (Description, Getting Started, Rationale, Design, TODO, License, Author)
  • LICENSE file exists and matches the README
  • REPO_POLICIES.md exists and version date is current — fetch from https://git.eeqj.de/sneak/prompts/raw/branch/main/prompts/REPO_POLICIES.md
  • .gitignore is comprehensive (OS, editor, agent scratch, language artifacts, secrets) — fetch from https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitignore if missing. An existing repo usually has a hand-written one that is never re-fetched, so check the entries rather than the file's presence.
  • .editorconfig exists — fetch from https://git.eeqj.de/sneak/prompts/raw/branch/main/.editorconfig
  • Dockerfile and .dockerignore exist; the Dockerfile carries a lint phase and a test phase, and the final stage carries a COPY --from= of a harmless file from each — fetch .dockerignore from https://git.eeqj.de/sneak/prompts/raw/branch/main/.dockerignore
  • Nothing has been appended after the final stage, and the gate phases are reachable from it. A stage nothing depends on is built only when --target names it, so a lost COPY --from= edge leaves docker build . passing while the gate never runs. Confirm by planting a violation, not by reading the file.
  • The gate phases invoke their tools directly, never through make lint or script/test — those are themselves a docker build and would recurse inside a build step
  • Every depth-independent pattern in .dockerignore carries a **/ prefix, only genuinely root-anchored entries such as .git are unprefixed, and .gitignore's patterns have not been transplanted unmodified — the transplanted form leaves config/.env and certs/server.key in the build context while reading as solved
  • .dockerignore excludes the repo's own host-built artifacts (compiled binaries, test binaries, coverage output), written root-anchored — /myapp, never **/myapp. An existing repo is where such a binary is likeliest to already be sitting in the build context, invisible to git.
  • .claude/ is in .gitignore (unanchored) and .claude in .dockerignore (anchored, no **/ prefix). Agent worktrees are entire checkouts of the repo, so they inflate the context by a multiple of it and can copy another session's unreviewed work into an image layer. If agents here run anywhere other than the repo root, the anchored entry misses services/api/.claude/: add anchored entries for those directories.
  • If the repo embeds a version in a binary, that version is computed on the host and passed with --build-arg VERSION=... by script/docker and script/cibuild, and no stage calls git describe. A tag-derived version additionally needs fetch-depth: 0 on the CI checkout step, which clones shallow and fetches no tags by default.
  • Gitea Actions workflow in .gitea/workflows/ runs script/cibuild on push — reference https://git.eeqj.de/sneak/prompts/raw/branch/main/.gitea/workflows/check.yml
  • Language-specific config:
    • Go: go.mod, go.sum, .golangci.yml (fetch from https://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml)
    • JS: package.json, yarn.lock, .prettierrc, .prettierignore (fetch from https://git.eeqj.de/sneak/prompts/raw/branch/main/.prettierrc and https://git.eeqj.de/sneak/prompts/raw/branch/main/.prettierignore)
    • Python: pyproject.toml
    • Docs/writing: .prettierrc, .prettierignore (same URLs as above)

Makefile and script/ Entrypoints

  • Makefile exists in root — reference https://git.eeqj.de/sneak/prompts/raw/branch/main/Makefile
  • Has targets: test, lint, fmt, fmt-check, check, docker, hooks
  • Target implementations live in script/ (scripts-to-rule-them-all); Makefile targets are thin shims calling them — model scripts at https://git.eeqj.de/sneak/prompts/raw/branch/main/script/<name>
  • script/precommit exists and the pre-commit hook (installed by script/install-precommit, shimmed by make hooks) runs it
  • README has an Entrypoints section documenting the script/ entrypoints and linking the standard
  • script/lint and script/test build their phase by name (docker build --no-cache --target <phase> -t <name>-<phase> .), and no host invocation anywhere in the repo can produce a lint verdict — grep for the linter's own name across script/, the Makefile and CI config, not just script/lint. A second path is likeliest here: a make lint-fast, an older host-versus-container branch, or a CI step calling the binary directly. script/fmt and script/fmt-check are expected hits and stay on the host.
  • Every docker build in script/ is tagged — an untagged one leaves a dangling image behind on every run, on every host and CI runner
  • script/cibuild runs script/bootstrap before script/check, and builds the image with --no-cache. Without the bootstrap the CI run dies in script/fmt-check, which runs the formatter on the host and finds nothing installed.
  • script/bootstrap installs no linter of its own — delete the block, its version variables and its call site. A JS repo's yarn install stays; it brings a linter along with every other dependency, and no verdict is taken from it.
  • make check does not modify any files in the repo
  • make test has a 90-second timeout and completes within the 60-second hard cap (over 20 seconds is green but must be filed as an improvement bug)
  • make test runs real tests, not a no-op (at minimum, import/compile check)
  • make check passes on current branch

Formatting

  • Platform-standard formatter is configured (black, prettier, go fmt)
  • Default formatter config, only exception: four-space indents (except Go)
  • All files pass make fmt-check

Git Hygiene

  • Pre-commit hook is installed (make hooks)
  • No secrets in the repo (.env, keys, credentials)
  • No mutable references in Dockerfiles or scripts (tags, @latest) — all pinned by cryptographic hash with version/date comment
  • Using yarn, not npm (JS projects)

Directory Structure

  • No unnecessary files in repo root
  • Files organized into canonical subdirectories (bin/, cmd/, docs/, internal/, static/, etc.)
  • Go migrations in internal/db/migrations/ and embedded in binary

HTTP Service Hardening (if targeting 1.0 and the repo is an HTTP/web service)

  • Security headers set on all responses (HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy)
  • Request body size limits enforced on all endpoints
  • Read/write/idle timeouts configured on the HTTP server (slowloris defense)
  • Per-handler execution time limits in place
  • Password-based auth endpoints are rate-limited
  • CSRF tokens on all state-mutating HTML forms
  • Passwords hashed with bcrypt, scrypt, or argon2
  • Session cookies use HttpOnly, Secure, and SameSite attributes
  • True client IP correctly detected behind reverse proxy (trusted proxy allowlist configured)
  • CORS restricted to explicit origin allowlist for authenticated endpoints
  • Error responses do not leak stack traces, SQL queries, or internal paths

Final

  • make check passes
  • script/cibuild succeeds in a fresh clone with nothing installed, which is what CI has, and demonstrably executed the checks — a sub-second build, or CACHED on a gate layer, means nothing ran
  • A planted lint violation fails both make lint and a plain docker build .; revert it afterwards
  • Commit and merge fixes before starting your actual task