Commit Graph
26 Commits
Author SHA1 Message Date
clawbot c32b10e77f Let fx own signals and the exit code in the server example (closes #86)
check / check (push) Failing after 2s
The server lifecycle example in `prompts/GO_HTTP_SERVER_CONVENTIONS.md` dropped its exit code, installed its own SIGINT/SIGTERM handler beside the one fx's `Run()` installs, and exited from a goroutine when Sentry could not start, so no stop hook ran.

fx now owns signals and the exit code: `main` calls `Run()`; a listen error shuts fx down with `fx.ExitCode(1)` through `fx.Shutdowner`; `enableSentry()` returns its error from the start hook; the stop hook shuts the HTTP server down within 5 seconds, flushes Sentry, and fails when requests are still running. The start hook builds the HTTP server before the listen goroutine so the stop hook can reach it. A new paragraph says who owns signals and the exit code.

Model: opus-5-5
2026-10-04 11:02:18 +02:00
clawbot c43c1f4bca Pin host Go tools by commit hash with go install (closes #37)
check / check (push) Failing after 2s
Writes sneak's 2026-09-09 ruling ("commit pinned installation, not pulled into deps") into the `prompts/REPO_POLICIES.md` bullet that says `script/bootstrap` installs a pinned tool by comparing versions: a Go tool a repo needs on the host is installed with `go install` pinned to a commit hash, naming the tool's main package, and is never tracked as a `go.mod` tool dependency or through a `tools.go` file, either of which pulls the tool's own dependencies into the repo's `go.mod` and `go.sum`.

golangci-lint is unchanged: no repo installs it on the host, and it stays pinned by its image digest.

Model: opus-5-5
2026-10-04 09:49:13 +02:00
clawbot 567944f8d8 Ignore hardware-backed SSH key files in the canonical ignore files (closes #81)
check / check (push) Failing after 2s
`ssh-keygen` names the private key of a key backed by a hardware security key `id_ecdsa_sk` or `id_ed25519_sk`. The canonical `.gitignore` and `.dockerignore` listed only `id_rsa`, `id_dsa`, `id_ecdsa` and `id_ed25519`, so a repository could commit these files or copy them into an image.

Both names are added beside their plain counterparts in each file's own style: unanchored in `.gitignore`, `**/`-prefixed in `.dockerignore`, case-folded with character ranges in both. A pattern matches the whole file name, so the `.pub` halves stay trackable and still reach the build context.

Model: opus-5-5
2026-10-04 09:14:52 +02:00
clawbot fa3202f214 Give package.json the MIT license field (closes #76)
check / check (push) Failing after 2s
`package.json` now carries `"license": "MIT"`, matching `LICENSE`. Without it yarn printed `warning package.json: No license field` and `warning No license field` each time `script/bootstrap` ran inside the Docker phases of `make check`. No other yarn warning appears in the bootstrap output.

Model: opus-5-5
2026-10-04 08:31:46 +02:00
clawbot 562b40bfe5 Keep agent guidance in one root AGENTS.md (closes #31)
check / check (push) Failing after 9s
Writes down sneak's 2026-08-22 ruling: the in-repo memory rule that older vendored copies of `REPO_POLICIES.md` still carry was retired, not lost.

`prompts/REPO_POLICIES.md` gains one bullet after the files a new repo must contain: guidance for coding agents lives in one `AGENTS.md` at the repository root, never under a file or directory named after one agent tool, and never split into separate memory files. `AGENTS.md` joins the files allowed in the repo root, which would otherwise forbid it. Both checklists get the matching item; the existing-repo one says to move such a file's content into `AGENTS.md` and delete it.

The Dockerfile finding at the end of the issue is tracked in #90.

Model: opus-5-5
2026-10-04 08:02:24 +02:00
clawbot 5805909fb9 Rewrite the -count=1 note to match the current files (closes #77)
check / check (push) Successful in 35s
The note under the canonical Go `make test` example in `prompts/REPO_POLICIES.md` named a cache-busting build argument that `--no-cache` replaced, and said Go's test result cache survived in earlier image layers. Neither is true of the current files.

The note now says where that cache can replay a pass: on a developer's machine, where the Makefile target runs, so both invocations there keep `-count=1`. The `test` phase of the `Dockerfile` has nothing to replay, since its base image holds no result for the repo's tests and no step before `go test` runs one, so it needs no `-count=1`. Go stores only passing results, so neither run can report a stored pass.

Model: opus-5-5
2026-10-04 07:31:48 +02:00
clawbot 3c1b435990 Fall back to dev when git describe prints nothing (closes #74)
check / check (push) Successful in 31s
The Makefile examples in `prompts/CODE_STYLEGUIDE_GO.md` and `prompts/GO_HTTP_SERVER_CONVENTIONS.md` now read `VERSION ?= $(or $(shell git describe --tags --always 2>/dev/null),dev)`.

When `git describe` prints nothing (outside a git checkout, or where git is missing or refuses the checkout) the old line stamped an empty version without a word; it now falls back to `dev`, the same way in every repo. The comment above each line says so.

In a Docker build stage with `.git` present, a real version needs git installed and the checkout trusted, as the canonical `Dockerfile` does; the `Dockerfile` already fails when the version comes out empty, `dev` or `unknown`.

Model: opus-5-5
2026-10-04 07:02:27 +02:00
clawbot 5de98c404e Keep each submodule's git config out of the build context (closes #75)
check / check (push) Successful in 28s
The canonical `.dockerignore` kept out `.git/config`, which can hold a credential, but not the `config` in each submodule's git directory under `.git/modules/`, nested again for a submodule's own submodules. It now also lists `.git/modules/**/config`, with one sentence in the comment above; `prompts/REPO_POLICIES.md` and both checklists say so in the same words.

The pattern stays under `.git/modules/` because `.git/**/config` would also drop a branch or tag named `config`, which `git describe` may need.

Known gap: a submodule whose name has a `config` path segment loses its whole git directory, so Go's version stamping fails the build loudly; tracked separately.

Model: opus-5-5
2026-10-04 05:31:51 +02:00
clawbot dcc0ba0b66 Fix git ownership and -race in the canonical Go Dockerfile (closes #73)
check / check (push) Successful in 52s
The canonical Go `Dockerfile` example in `prompts/REPO_POLICIES.md` had two defects.

The test phase ran `go test -race` on the alpine Go image, which has no C compiler, so `-race` failed before any test ran. The test phase now uses the Debian Go image, pinned by digest like the others.

A build context sent as a tar stream keeps the sender's file owners, so git refused the checkout and the version step failed the build. The builder stage now runs `git config --system --add safe.directory /src`; the policy and both checklists say why in the same words.

The builder's `apk add --no-cache git` line is unchanged: whether it must be pinned is the open owner question on #72.

Model: opus-5-5
2026-10-04 04:31:51 +02:00
clawbot 343628fb3a Pin golangci-lint v2.14.0; disable exhaustruct_v5 (closes #65)
check / check (push) Successful in 37s
The canonical golangci-lint moves from v2.12.2 to v2.14.0, built with go1.27: v2.12.2 refuses a module whose `go` directive names 1.27 or later. The policy now states the rule: the `go` directive must not name a newer Go minor version than the one golangci-lint was built with.

From v2.13.0, `default: all` turns on `exhaustruct_v5`, the successor of the deprecated `exhaustruct`. `.golangci.yml` disables it beside the old name, which stays listed or its deprecation warning returns.

v2.12.2 rejects the new `.golangci.yml`, so a repo changes the lint phase digest and re-vendors `.golangci.yml` in one commit; both checklists point to that rule.

Model: opus-5-5
2026-10-04 03:32:08 +02:00
clawbot 7ea5cdcdcd Cover more secret shapes in the canonical .gitignore (closes #38)
check / check (push) Successful in 23s
The canonical .gitignore matched only .env, .env.*, *.pem and *.key, so prod.env, .envrc, *.p12 and *.pfx bundles, and the SSH private keys id_rsa, id_dsa, id_ecdsa and id_ed25519 could be committed. The secrets section now covers the same shapes as the canonical .dockerignore, written to gitignore's own rules: unanchored, no **/ prefix, character ranges for case. example.env and sample.env stay trackable through negations, and the comment tells a repository to add its own negation for any other committed template.

Judgement call: the existing entries were rewritten with character ranges, which only widens them, and the bare .env line is dropped because *.env covers it.

Model: opus-5-5
2026-10-03 17:39:40 +02:00
clawbot 507a57e813 Derive the image version from git; send .git without its config (closes #69, closes #71)
check / check (push) Successful in 23s
The canonical documents told every repo to exclude .git from the build
context, default ARG VERSION to dev and never run git describe in a
build stage, so an image built from a clone with no build argument
reported dev. .dockerignore now sends .git but keeps out .git/config,
which can hold a credential. The Dockerfile example installs git, takes
the VERSION build argument when one is given and otherwise
git describe --tags --always, and fails when .git exists but the version
is empty, dev or unknown. The policy and both checklists state the rule
in the same words, including that a plain docker build . with no build
arguments must succeed.

Model: opus-5-5
2026-10-02 04:38:10 +02:00
clawbot 2ae9391b26 Read the architecture at run time, not via a Buildarch ldflag (closes #66)
check / check (push) Successful in 25s
The Go styleguide and the HTTP server conventions no longer pass the
build architecture in through the Makefile. The Buildarch variable,
globals field and BUILDARCH Makefile lines are removed from every
example; the styleguide example prints runtime.GOARCH, and the
logger's Identify logs "arch", runtime.GOARCH. The styleguide item
gains one sentence saying so.

Model: opus-5-5
2026-10-02 01:03:38 +02:00
clawbotandsneak ed5ed236b1 Migrate canonical .golangci.yml to gomodguard_v2, with a block list (#55)
check / check (push) Successful in 30s
Option-2 answer to sneak's ruling of 2026-08-19 on
sneak/homoicon#4: migrate to the successor, with
settings. Closes #25.

## The change

`golangci-lint` v2.12.0 deprecated `gomodguard`, and this config sets
`linters.default: all`, so it is enabled everywhere and warns on every run.

- `gomodguard` joins `wsl` in `linters.disable` under a shared "deprecated"
  comment. The warning is attached to the old name, so disabling it is what
  silences it.
- `gomodguard_v2` is named in `linters.enable`, a no-op under `default: all`
  that gives the settings block a visible owner.
- Blocked, each restating a decision already recorded in the Go package
  defaults: `rs/zerolog` → `log/slog`; the pre-fork `go-redis/redis` →
  `redis/go-redis/v9`; `sergi/go-diff` and `hexops/gotextdiff` → `go-udiff`.
  Every entry matches the module path exactly, so the pre-fork go-redis takes
  three: `go-redis/redis`, `/v7`, `/v8`. A prefix would also cover
  `go-redis/redismock`, the test double for the successor recommended here.

Deliberately absent: recorded rejections that vendoring repos still require
(`mattn/go-sqlite3`, `gorm.io/gorm`, `pmezard/go-difflib`), plus `urfave/cli`
and unversioned `go-chi/chi`. Blocking those would redden repos mid-migration
on their next re-vendor.

## After merge

The file's sha256 moves from
`d10f47ef5e0d8620efd62275b016a7de8fd5abedf333922eec86fe4abc06176e` to
`a79b63a254602a5318db5d0e9a06bc71b84bf0c1d896305229d8bfed1d1b1776`, so every
vendoring repo mismatches. #60 is the
propagation brief; it and the record on
#25 carry this value.

## Disclosures

- Judgement call: `wsl` moved two lines down to share the "deprecated" comment.
  No behaviour change, but it widens the diff.
- The `go.mod` survey and the settings-block probe are on
  #25.
- Unverified: the linter was not run against each vendoring repo; the per-repo
  claim rests on reading their `go.mod` files.
- `make check` exit 0.

Model: opus-5
Co-authored-by: Jeffrey Paul <sneak@noreply.example.org>
Reviewed-on: #55
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-09-09 14:04:18 +02:00
58eafaf4c2 Add -count=1 to the canonical Go make test example (#45)
check / check (push) Successful in 7s
Answers #44: the canonical Go `make test` target omitted `-count=1`, so Go replayed cached successful results and the target could exit 0 having executed no test. Every repository that copied it inherited that false green.

The change adds `-count=1` to both `go test` invocations in the example in `REPO_POLICIES.md`, with a short paragraph saying why, and records the step in `TODO.md`. It defeats only the test-result cache, not the build cache, so it costs the suite's runtime and no recompilation. It is independent of the Docker layer cache that #26 addresses.

Rebased onto current `main`; the check is green. Repositories pick it up the next time each vendors the canonical files.

Model: opus-5 (change); fable-5-1 (this description)
Co-authored-by: sneak <sneak@sneak.berlin>
Co-authored-by: clawbot <cai2025@acidhou.se>
Co-authored-by: Jeffrey Paul <sneak@noreply.example.org>
Reviewed-on: #45
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-09-09 13:41:57 +02:00
clawbotandsneak fbec5a523b Enable depguard so a non-test file cannot import test support (#59)
check / check (push) Successful in 51s
`depguard` was in the disable list. It is now enabled with one rule,
`test-support`: in files that are neither test files nor inside a package whose
directory name ends in `test`, the imports named under `deny` are refused.
Canonical denies `net/http/httptest`, which serves tests only and is the same
in every repository.

This replaces `internal/testimportgate` in sneak/homoicon, a package whose only
job was to refuse a non-test Go file importing an in-module package whose last
path segment ends in `test`. sneak ruled on
sneak/homoicon#1029 that the rule moves into linter
configuration here.

depguard cannot express that rule generically. Its package lists are prefix
lists -- its own README says so, and I confirmed it: `*test`, `**test` and
`$gomod/**test` each match nothing, while a full import path matches. "In
module" is not generic either, since the module path differs per repository.
And depguard refuses a rule with no allow or deny list, so this file cannot
ship the rule pre-armed and empty for each repository to fill in.

The closest expressible rule is the one here. The file half is generic and
exact; the package half is a deny list each repository extends with its own
test-support packages, by full import path. REPO_POLICIES.md now says that list
is the one part of a vendored copy a repository may add to.

Tested with golangci-lint v2.12.2 on a scratch module: a production file
importing a denied `*test` package fails, and the same import from a `_test.go`
file and from inside the `*test` package passes. `make check` here is green.

Model: opus-5
Co-authored-by: sneak <sneak@sneak.berlin>
Reviewed-on: #59
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-09-08 05:14:43 +02:00
clawbotandsneak f77d785bed Scope the .golangci.yml agent prohibition to vendored copies (#49)
check / check (push) Successful in 9s
SPECULATIVE and ahead of your ruling — nothing here is urgent and closing it costs nothing. One sentence of policy prose changed; no config file is touched.

## The contradiction

`REPO_POLICIES.md` line 266 currently reads:

&gt; `.golangci.yml` is standardized and must _NEVER_ be modified by an agent, only manually by the user.

Stated unqualified, that forbids an agent from modifying `.golangci.yml` **anywhere** — including the canonical copy in this repo, which is the only place it can ever be fixed. An agent that wants to remediate a linter problem must either violate the rule or leave the problem standing. A rule that cannot be complied with and satisfied at the same time gets resolved ad hoc, differently by each reader, which is the worst of both outcomes it was trying to produce.

This is not hypothetical. It has already cost real time:

- The `gomodguard` deprecation (#25) has been open since 2026-08-07 and still prints on every lint run in every consuming Go repo.
- One agent read the rule as binding here and **declined to open even a speculative branch**, so the fix was not written at all on that pass.
- #47 exists only because a later request was explicit enough to override the reading, and its lead comment asks for exactly this ruling before the PR itself can be judged on its merits.
- The same warning is refiled downstream as sneak/homoicon#4, where it is correctly marked owner-only and correctly punted upstream.

Each new agent that meets the rule reruns this whole argument.

## The change

Scope the prohibition to the vendored copy, and name the one legitimate path by which the config can change:

```
- `.golangci.yml` is standardized. The vendored copy in a consuming repo must
  _NEVER_ be modified by an agent: fetch it from
  `https://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml` and keep it
  byte-identical, so that no repo can quietly loosen its own linting. Linter
  configuration changes are made to the canonical copy in the `prompts` repo and
  reach consuming repos by re-vendoring; an agent may open a PR against
  canonical, which only the user merges.
```

The version pin sentence that followed is unchanged.

This keeps the property the rule exists for — no repo silently weakens its own linting, and divergence from canonical stays detectable — while removing the reading that freezes canonical itself. Your control is not reduced: an agent may open a PR here, and only you merge it.

## Scope of the wording sweep

I grepped every `.md` in the repo for the absolute phrasing. It appears in **exactly one place**, `prompts/REPO_POLICIES.md` lines 266-267.

`EXISTING_REPO_CHECKLIST.md` (line 39) and `NEW_REPO_CHECKLIST.md` (line 63) both mention `.golangci.yml`, but only as "fetch from `https://git.eeqj.de/sneak/prompts/raw/branch/main/.golangci.yml`" — an instruction to vendor canonical verbatim, which is exactly what the scoped rule says. Neither carries a prohibition, so neither needs changing and neither is left contradicting the other. `REPO_POLICIES.md` line 414 lists `.golangci.yml` as a required file, also unaffected.

Note that the repo-root `REPO_POLICIES.md` is a symlink to `prompts/REPO_POLICIES.md`, so the single edit covers both paths.

## Deliberately NOT included

This PR does **not** change `.golangci.yml`. The `gomodguard` fix stays in #47 so the two can be judged separately — the policy question is worth settling on its own terms regardless of what you decide about that config change, and merging them would collapse two decisions into one.

## Unrelated observation, for the record

While verifying #47 against a scratch `sneak/homoicon` clone, I found that homoicon's vendored `.golangci.yml` is sha256 `391ea68e637432980f1db0776076f51578fa58193bbd17f4b40ad725975e21f8`, while canonical `main` is `021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb`. The whole difference is a three-line comment recording a one-time agent edit you authorized on 2026-08-07; the config is functionally identical.

That matters only if you ever want a hash-based drift guard against canonical, which #25 floats as an offline alternative to `golangci-lint config verify`: such a guard would already report homoicon as drifted on day one. Worth knowing before building one. No change proposed here.

## Validation

`make check` passes (`prettier --check '**/*.md' --tab-width 4 --prose-wrap always`: all matched files clean). `make fmt` produced no further changes. `last_modified` in the front matter updated to 2026-08-19 per this file's own rule.

Co-authored-by: sneak <sneak@sneak.berlin>
Co-authored-by: Jeffrey Paul <sneak@noreply.example.org>
Reviewed-on: #49
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-08-30 06:26:19 +02:00
clawbotandsneak 3f8201d532 Require thin cmd/ entrypoints: all logic in internal/ or pkg/ (#54)
check / check (push) Successful in 13s
Codifies your ruling (2026-08-30, filed as homoicon issue 555): no project logic outside `internal/` or `pkg/`; each `cmd/<name>/` is a single `main.go` whose body is one call into library code.

- `CODE_STYLEGUIDE_GO.md`: strengthens the "keep `main` small" rule to the single-call form and adds the no-logic-outside-`internal/`-or-`pkg/` rule.
- `REPO_POLICIES.md`: annotates `cmd/` in the canonical subdirectory list accordingly. (Root copy is a symlink; one edit covers both.)

Co-authored-by: sneak <sneak@sneak.berlin>
Reviewed-on: #54
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-08-30 04:20:42 +02:00
clawbotandclawbot a8686891ba Raise org-wide make test cap to 60s, backstop timeout to 90s (#42)
check / check (push) Successful in 4s
## The question this answers

Is the 60-second test-time cap the new **org-wide** ceiling, or an approved
**dnswatcher-only** divergence?

- Question: #41
- Origin: sneak/dnswatcher#93

This PR implements **org-wide**.

## The ruling

On sneak/dnswatcher#93 (comment) (2026-08-09),
verbatim:

&gt; make the cap 60s in both and never use mocking, always use live resolvers and
&gt; assume the build and run environments have full unmodified unrestricted
&gt; internet access. it is ok if they fail due to a bad build environment that
&gt; alters dns packets.

And on #41 (comment), disambiguating
the scope:

&gt; org wide. the hard cap is 60 for ci/green, but over 20s should be filed as an
&gt; improvement bug.

That second comment landed after this work was started, and it confirms the
option implemented here. The two-tier shape it describes (60s hard, 20s target,
overage filed as a bug) is encoded in the policy text.

## What changed, and the number chosen

The backstop moves from `30s` to **`90s`**.

The old pairing was incoherent under the new cap: a 60-second ceiling with a
30-second `-timeout` means the timeout kills the suite long before the ceiling
is reached, so the ceiling would never be the thing that fails. The backstop has
to sit above the cap, where it does its actual job of catching a hung test
rather than a merely slow one. `90s` preserves the 1.5x backstop-to-cap ratio
the old `20s`/`30s` pair already had, so the relationship between the two
numbers is unchanged and only the scale moves.

Every place a number changed:

| File | What |
| --- | --- |
| `prompts/REPO_POLICIES.md` | Prose ceiling: `20 seconds` to `60 seconds`, plus the new 20s target / improvement-bug tier |
| `prompts/REPO_POLICIES.md` | Backstop prose: `30-second timeout` to `90-second timeout`, with the rationale for why it exceeds the cap |
| `prompts/REPO_POLICIES.md` | Go example Makefile snippet, first run: `go test -timeout 30s` to `-timeout 90s` |
| `prompts/REPO_POLICIES.md` | Go example Makefile snippet, verbose rerun: `go test -timeout 30s` to `-timeout 90s` |
| `prompts/EXISTING_REPO_CHECKLIST.md` | `make test` has a `30-second` timeout, to `90-second` timeout plus the 60s hard cap and the 20s filing rule |
| `prompts/NEW_REPO_CHECKLIST.md` | `script/test` / `make test` entrypoint line: `30-second timeout` to `90-second timeout, 60-second hard cap on wall time` |

I swept the whole repo for `20 second`, `30-second`, `20s`, `30s`, `timeout 20`,
`timeout 30`, and `under 20`/`under 30`. After this change the only remaining
occurrences of `20` in a test-timing context are the two intentional references
to the new 20-second target. The other `timeout` hits in the repo are unrelated
(`.golangci.yml` lint timeout, HTTP server `ReadTimeout`/`WriteTimeout` examples,
`middleware.Timeout`) and were left alone.

One deliberate non-change: the Python example Makefile snippet in
`prompts/REPO_POLICIES.md` carries no timeout flag today and still carries none.
`pytest` has no built-in timeout, so adding one would mean mandating the
`pytest-timeout` plugin org-wide, which is a new dependency requirement rather
than a renumbering, and outside what was ruled on. It is a pre-existing gap
between the prose and that snippet, not one this PR introduces. Happy to file it
separately or add `--timeout=90` here if you want it in scope.

## The alternative that was not implemented

**Keep canonical at 20s and let `sneak/dnswatcher` carry a documented per-repo
divergence.** That was the recommendation originally written up in
#41, on the reasoning that the 20s
ceiling is doing real work in repos with fast deterministic suites and only
dnswatcher needs the headroom.

Org-wide was chosen instead for two reasons. First, the pressure is not specific
to DNS: any repo whose tests exercise real infrastructure over the network
inherits the same variance, and there is no principled line that admits
dnswatcher and excludes the next such repo. Second, and more decisively,
`REPO_POLICIES.md` is a vendored file. A sanctioned per-repo divergence in a
vendored file is indistinguishable, on inspection, from a stale vendored copy:
the next re-vendoring silently reverts the divergence, and nobody reading a
consuming repo can tell whether the number they are looking at is an intentional
exception or drift. That is the bidirectional-drift problem already tracked in
#31. The two-tier cap gets the same
outcome without the drift, since a fast repo that regresses from 4s to 45s still
generates an improvement bug.

## Status

This PR was opened speculatively, ahead of a decision, on the standing "open it
rather than wait" instruction. The scope question has since been answered
org-wide in the issue, but the specific backstop value of `90s` and the two-tier
wording are still my proposals rather than anything ruled on, so closing this or
sending it back for a different number is a perfectly fine outcome.

`make check` passes; `make fmt` was run and the result is included (it was a
no-op, the edits were already prettier-conformant).

`sneak/dnswatcher` is landing the matching 60s edit to its vendored copy in
parallel, and will match whichever way this is decided.

Co-authored-by: clawbot <clawbot@eeqj.de>
Reviewed-on: #42
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-08-10 16:13:31 +02:00
0f8efafe68 Set canonical .golangci.yml to the org-standard v2 config (golangci-lint v2.12.2) (#24)
check / check (push) Has been cancelled
Requested by sneak.

Sets the canonical `.golangci.yml` to the org-standard v2-schema config already deployed byte-identical across the org's Go repos (vaultik, sfdupes, attrsum, upaas, simplelog, mfer, secret, rgoue, bsfirehose). sha256: `021cc83f4e6fc7c31b95b34b846723dfcf20b66b7baeea1dc40406e643346bcb`.

Why: settings live under `linters.settings`, so the lll/funlen/cyclop/dupl thresholds actually apply under golangci-lint v2. The old canonical file kept them under top-level `linters-settings`, which v2 ignores.

Version note: golangci-lint v2.12.2 tag = commit `c0d3ddc9cf3faa61a4e378e879ece580256d76e5`, recorded for consuming repos. This repo itself has no version pins; the `v2.x.x` / `@sha256:...` strings in `prompts/REPO_POLICIES.md` are intentional placeholders and are unchanged.

Known informational note: this config does not disable the deprecated `gomodguard` linter, so golangci-lint 2.12.x prints a deprecation warning. Harmless, accepted.

Matches dnswatcher PR #96: sneak/dnswatcher#96

Verification: `make check` green (prettier fmt-check on all markdown) after `make fmt`; `.golangci.yml` sha256 verified as `021cc83f...` matching the org-standard file.
Co-authored-by: sneak <sneak@sneak.berlin>
Co-authored-by: clawbot <clawbot@eeqj.de>
Reviewed-on: #24
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-08-07 23:24:05 +02:00
4b64c213f8 style: strengthen constructor naming and Params struct rules (#19)
check / check (push) Successful in 5s
Per sneak's instruction:

- Constructors **must** be `New()`, `From<Something>()`, or `NewThing()` (multi-type packages only)
- Strongly discourage creative names (`Create`, `Make`, `Build`, `Init`)
- Constructors **must** use a `Params` struct (or `ThingParams`) for 2+ arguments — no exceptions
- Single obvious argument (`ctx`, bytes) is the only exception
- `context.Context` does not count against the argument limit (already documented)

Co-authored-by: user <user@Mac.lan guest wan>
Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de>
Reviewed-on: #19
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-03-20 07:06:03 +01:00
clawbotandclawbot 777822e50e docs: document conditional -v test rerun pattern in REPO_POLICIES.md (#21)
check / check (push) Successful in 8s
## Summary

Adds the conditional verbose test rerun pattern as a policy recommendation in REPO_POLICIES.md.

Per sneak's request from [sneak/chat PR #82](sneak/chat#82): document the pattern where `make test` runs tests without `-v` first, then automatically reruns with `-v` on failure for full diagnostic output.

## Changes

**`prompts/REPO_POLICIES.md`** (root `REPO_POLICIES.md` is a symlink to this):
- Added new policy bullet after the `make test` timeout rule
- Explains the rationale: clean CI/Docker build logs on success, full verbose output on failure
- Includes a generic shell pattern template
- Includes concrete Go and Python examples
- Documents that `exit 1` ensures the target always fails after a rerun (the rerun is solely for diagnostic output)
- Updated `last_modified` from 2026-03-12 to 2026-03-18

## The Pattern

```makefile
test:
	@go test -timeout 30s -race -cover ./... || \
		{ echo "--- Rerunning with -v for details ---"; \
		  go test -timeout 30s -race -v ./...; exit 1; }
```

- **On success**: concise package summaries only, no per-test noise
- **On failure**: automatic verbose rerun shows every test case and assertion
- **Always fails**: `exit 1` ensures the build fails regardless of second run's exit code

closes #20

Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de>
Reviewed-on: #21
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-03-19 22:53:40 +01:00
clawbotanduser 1c84344978 docs: document fail-fast lint stage pattern for Dockerfiles (#18)
check / check (push) Successful in 5s
Documents the multistage Docker build pattern we now use across repos (chat, pixa, etc.) where a separate `lint` stage runs `make fmt-check` and `make lint` independently from the build stage.

Key additions to REPO_POLICIES.md:
- Full Dockerfile template showing the lint → build → runtime stage pattern
- Explanation of `COPY --from=lint /src/go.sum /dev/null` as the BuildKit dependency trick
- Handling `//go:embed` placeholders in the lint stage
- CGO/system library notes for the lint stage
- Clarification that tests run in the build stage, not the lint stage

Reference implementations: `sneak/chat`, `sneak/pixa`.

Co-authored-by: user <user@Mac.lan guest wan>
Reviewed-on: #18
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-03-18 03:59:02 +01:00
41005ecbe5 Add HTTP service hardening policy for 1.0 releases (#17)
check / check (push) Successful in 8s
Closes #16

Adds a comprehensive HTTP/web service security hardening policy to `REPO_POLICIES.md` that must be satisfied before tagging 1.0. The policy covers all items sneak specified (without limitation):

**Security headers** — HSTS (min 1 year, includeSubDomains), CSP (restrictive `default-src 'self'` baseline), X-Frame-Options / frame-ancestors, X-Content-Type-Options: nosniff, Referrer-Policy, Permissions-Policy.

**Request/response limits** — max request body size on all endpoints, max response size for paginated APIs, ReadTimeout + ReadHeaderTimeout (slowloris defense), WriteTimeout, IdleTimeout, per-handler execution time limits.

**Authentication & session security** — rate limiting on password-based auth (API keys exempt as high-entropy), CSRF tokens on state-mutating forms (header-auth APIs exempt), bcrypt/scrypt/argon2 for passwords, session cookies with HttpOnly + Secure + SameSite.

**Reverse proxy awareness** — true client IP detection via X-Forwarded-For/X-Real-IP with trusted proxy allowlist (never trust unconditionally).

**CORS** — explicit origin allowlist for authenticated endpoints; wildcard only for public unauthenticated read-only APIs.

**Error handling** — no leaking stack traces, SQL queries, file paths, or implementation details to clients.

**TLS** — HSTS and secure cookie flags required regardless of whether the service terminates TLS directly or sits behind a reverse proxy.

The policy is explicitly non-exhaustive (defense-in-depth: "when in doubt, harden").

Also adds corresponding checklist sections to `EXISTING_REPO_CHECKLIST.md` and `NEW_REPO_CHECKLIST.md` so that HTTP hardening is verified during repo setup and 1.0 preparation.

Co-authored-by: user <user@Mac.lan guest wan>
Co-authored-by: clawbot <clawbot@eeqj.de>
Reviewed-on: #17
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-03-11 02:11:32 +01:00
clawbotandclawbot eb6b11ee23 policy: no build artifacts in repos (#15)
check / check (push) Successful in 5s
Add policy rule: build artifacts and code-derived data must not be committed to repos if they can be generated during the build process.

Notable exception: Go protobuf-generated files (`.pb.go`) may be committed because `go get` downloads source but does not execute build steps.

This addresses feedback from sneak/chat PR [#61](sneak/chat#61).

Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de>
Reviewed-on: #15
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-03-10 10:34:57 +01:00
clawbotanduser 58d564b641 Update LLM prose tells: new patterns + lol section (#8)
check / check (push) Successful in 3s
Updates LLM_PROSE_TELLS.md with three new patterns (two-clause compound sentence, almost-hedge, unnecessary contrast), the lol section with conversation excerpts, fixes for instances of these patterns throughout, and a bracket escaping fix for prettier idempotency. Checklist is now 24 items.

Co-authored-by: user <user@Mac.lan guest wan>
Reviewed-on: #8
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-03-04 23:29:51 +01:00