Unify the gate: root make check must cover the backend, and CI must route through script/ #16

Open
opened 2026-08-09 03:37:45 +02:00 by clawbot · 0 comments
Collaborator

Problem

The repo has two disconnected build systems, and the root gate does not actually gate the whole repo. Verified on main at fbfe1df.

1. Root make check ignores the backend entirely

Makefile check shims to script/check, which runs the frontend yarn build plus prettier --check. It never touches backend/. Confirmed by running it: root make check passes while exercising zero Go code.

This means the "main must always pass make check, no exceptions" policy is being satisfied vacuously — the Go backend could be entirely broken and the root gate would stay green. Anyone (or any pre-commit hook) running make check at the root gets false assurance.

2. The backend is not on scripts-to-rule-them-all

REPO_POLICIES.md requires that "the implementation of each Makefile target lives in an executable script in script/ ... and the Makefile targets are thin shims that call them." backend/Makefile is a full standalone Makefile with inline recipes (go build, go test, golangci-lint run, gofmt) and no script/ indirection. It also violates the "always use Makefile targets instead of invoking the underlying tools directly" rule at the layer below.

3. Two competing pre-commit hook installers, one clobbers the other

  • script/install-precommit (shimmed by root make hooks) installs a hook running script/precommit.
  • backend/Makefile's hooks target writes .git/hooks/pre-commit with the literal body cd backend && make check.

Both target the same single .git/hooks/pre-commit path. Whichever ran last wins, so the developer silently ends up gating on only one half of the repo. There must be exactly one hook installer, and the hook must gate the whole repo.

4. CI invokes docker build directly instead of through script/

.gitea/workflows/check.yml:

- run: script/cibuild
- run: docker build -f Dockerfile.backend .

The second step is a raw tool invocation, bypassing the script/ layer that is supposed to be the single source of truth for how the repo builds. Policy: the workflow runs script/cibuild; script/cibuild runs the docker build(s).

Definition of done

  • Root make check fails if either the frontend or the backend is broken. Demonstrate this: deliberately break a Go file, confirm root make check fails, revert.
  • The backend's test/lint/fmt-check implementations live in script/ entrypoints, and any retained backend/Makefile targets are thin shims. Whether that means extending the root script/* files to cover both halves or adding backend/script/* is an implementation choice — pick one, apply it consistently, and document the choice in the PR description.
  • script/cibuild builds both images (frontend Dockerfile and Dockerfile.backend). .gitea/workflows/check.yml contains exactly one build step: - run: script/cibuild. No raw docker build anywhere in the workflow.
  • Exactly one pre-commit hook installer remains. backend/Makefile's hooks target is removed. make hooks at the root installs a hook whose script/precommit run gates the whole repo (frontend and backend).
  • The README Entrypoints section is updated to reflect what each script now does, including backend coverage.
  • make check passes at the root, and covers the Go code.
  • script/cibuild succeeds locally.
  • make check does not modify any tracked file (policy: "make check must not modify any files in the repo"). Verify git status --short is clean afterwards.
  • TODO.md updated in the same commit.
  • Commit title ends with (closes #N).

Implementation requirements

  • script/ files must be POSIX sh (#!/bin/sh, set -eu, no bashisms), locate the repo root with $(cd "$(dirname "$0")/.." && pwd -P), and cd there before acting.
  • Keep script/projectname and any other scripts that policy says stay byte-identical across repos unchanged.
  • Do not change the golangci-lint version or .golangci.yml here — that is issue #14. If #14 has already landed, just do not regress it.
  • Do not fold in the backend make test flag changes (-race, -cover, conditional verbose rerun) — that is a separate issue.
  • Total make test runtime must stay under 20 seconds with a 30-second timeout enforced; docker builds must stay under 5 minutes.
  • make targets and script/ entrypoints only — never raw go, yarn, gofmt, or golangci-lint.
  • No attribution trailers in the commit message.
## Problem The repo has two disconnected build systems, and the root gate does not actually gate the whole repo. Verified on `main` at `fbfe1df`. ### 1. Root `make check` ignores the backend entirely `Makefile` `check` shims to `script/check`, which runs the frontend `yarn build` plus `prettier --check`. It never touches `backend/`. Confirmed by running it: root `make check` passes while exercising zero Go code. This means the "`main` must always pass `make check`, no exceptions" policy is being satisfied vacuously — the Go backend could be entirely broken and the root gate would stay green. Anyone (or any pre-commit hook) running `make check` at the root gets false assurance. ### 2. The backend is not on scripts-to-rule-them-all `REPO_POLICIES.md` requires that "the implementation of each Makefile target lives in an executable script in `script/` ... and the Makefile targets are thin shims that call them." `backend/Makefile` is a full standalone Makefile with inline recipes (`go build`, `go test`, `golangci-lint run`, `gofmt`) and no `script/` indirection. It also violates the "always use Makefile targets instead of invoking the underlying tools directly" rule at the layer below. ### 3. Two competing pre-commit hook installers, one clobbers the other - `script/install-precommit` (shimmed by root `make hooks`) installs a hook running `script/precommit`. - `backend/Makefile`'s `hooks` target writes `.git/hooks/pre-commit` with the literal body `cd backend && make check`. Both target the same single `.git/hooks/pre-commit` path. Whichever ran last wins, so the developer silently ends up gating on only one half of the repo. There must be exactly one hook installer, and the hook must gate the whole repo. ### 4. CI invokes `docker build` directly instead of through `script/` `.gitea/workflows/check.yml`: ```yaml - run: script/cibuild - run: docker build -f Dockerfile.backend . ``` The second step is a raw tool invocation, bypassing the `script/` layer that is supposed to be the single source of truth for how the repo builds. Policy: the workflow runs `script/cibuild`; `script/cibuild` runs the docker build(s). ## Definition of done - [ ] Root `make check` fails if **either** the frontend or the backend is broken. Demonstrate this: deliberately break a Go file, confirm root `make check` fails, revert. - [ ] The backend's test/lint/fmt-check implementations live in `script/` entrypoints, and any retained `backend/Makefile` targets are thin shims. Whether that means extending the root `script/*` files to cover both halves or adding `backend/script/*` is an implementation choice — pick one, apply it consistently, and document the choice in the PR description. - [ ] `script/cibuild` builds **both** images (frontend `Dockerfile` and `Dockerfile.backend`). `.gitea/workflows/check.yml` contains exactly one build step: `- run: script/cibuild`. No raw `docker build` anywhere in the workflow. - [ ] Exactly one pre-commit hook installer remains. `backend/Makefile`'s `hooks` target is removed. `make hooks` at the root installs a hook whose `script/precommit` run gates the whole repo (frontend and backend). - [ ] The README **Entrypoints** section is updated to reflect what each script now does, including backend coverage. - [ ] `make check` passes at the root, and covers the Go code. - [ ] `script/cibuild` succeeds locally. - [ ] `make check` does not modify any tracked file (policy: "`make check` must not modify any files in the repo"). Verify `git status --short` is clean afterwards. - [ ] `TODO.md` updated in the same commit. - [ ] Commit title ends with ` (closes #N)`. ## Implementation requirements - `script/` files must be POSIX sh (`#!/bin/sh`, `set -eu`, no bashisms), locate the repo root with `$(cd "$(dirname "$0")/.." && pwd -P)`, and `cd` there before acting. - Keep `script/projectname` and any other scripts that policy says stay byte-identical across repos unchanged. - Do **not** change the golangci-lint version or `.golangci.yml` here — that is issue #14. If #14 has already landed, just do not regress it. - Do not fold in the backend `make test` flag changes (`-race`, `-cover`, conditional verbose rerun) — that is a separate issue. - Total `make test` runtime must stay under 20 seconds with a 30-second timeout enforced; docker builds must stay under 5 minutes. - `make` targets and `script/` entrypoints only — never raw `go`, `yarn`, `gofmt`, or `golangci-lint`. - No attribution trailers in the commit message.
clawbot added this to the 1.0.0 milestone 2026-08-09 03:37:45 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/netwatch#16