docs: describe how contribution actually works #30

Merged
ullrich merged 1 commit from docs/contributing into main 2026-07-27 21:28:49 +00:00
Owner

Implements options 1+2 from the discussion: keep registration closed, document the paths that actually exist.

The problem

README.md said "Human contributions are welcome!" while GitHub was retired and git.ullrich.is reports "Registration is disabled". So an outsider could not fork, could not open a PR, and could not file an issue — and there was no CONTRIBUTING.md explaining any alternative. The project was promising something impossible, same class as the 404s fixed in #26.

What this adds

Two real paths in, rather than opening registration:

  1. Request an account by email. After that everything works normally — fork, branch, PR, review, merge. Recommended for anything beyond a one-liner, since you get CI results and inline review.
  2. Email a patch (git format-patch). Needs no account anywhere, and git am preserves the contributor as commit author, so authorship credit survives into the history.

Filing an issue without an account is covered too — email it, and it gets filed with credit.

Explains why registration is closed, so it reads as a decision rather than neglect: the instance shares a box with other services, and open signup would mean CI running unreviewed code from unknown branches on the same runners that build and deploy production. That's the real reason, and it's a more honest thing to say than "personal instance".

Sets previously-undocumented expectations:

  • every CI / * check must pass (main is protected)
  • external contributions are squash-merged, and Forgejo signs the result with the instance key — so contributors don't need GPG configured
  • no merge queue, so a long-open branch wants a rebase before final review
  • larger changes start as an OpenSpec proposal, not as code
  • non-goals are named: zero data collection in the Planner, no tracking/analytics, data must stay exportable. A change that violates those gets declined however well written — better to say so before someone spends a weekend on it.

Plus the conventions that actually trip people up: explicit routes.ts registration (fails as a 404, not a build error), i18n for all user-facing strings, co-located tests, new packages needing both Dockerfiles.

There's also a short, plain note that most of the codebase is AI-authored — because it changes what's useful to contribute. Design judgement, real-world testing, and "does this feature earn its complexity" are worth more here than volume of code.

Verified rather than asserted

A contribution guide that lies is worse than none, so every factual claim was checked:

claim result
anonymous clone over HTTPS works OK — cloned at 18560b3 with GIT_TERMINAL_PROMPT=0
issue tracker publicly viewable 200
all 8 linked paths exist OK
both app/routes.ts exist OK
all 6 referenced pnpm scripts exist OK
main requires CI / * confirmed via branch protection API

Also drops a stale "public GitHub issue" line in SECURITY.md that the #26 sweep missed.

Two things needing you

  1. contribute@trails.cool must exist as a mailbox or alias. It's the one claim I couldn't verify, and the whole document routes through it — if you'd rather use a different address, it's a one-line change in three places.
  2. Unverified mechanic worth a real test if you ever open registration: whether require_signed_commits rejects a PR whose own commits are unsigned. Squash-merging sidesteps it (the single landed commit is instance-signed), which is why the doc specifies squash for external contributions — but if you ever accept merge commits from contributors, that needs testing with a throwaway account first, because getting it wrong blocks the merge entirely.
Implements options 1+2 from the discussion: keep registration closed, document the paths that actually exist. ## The problem `README.md` said *"Human contributions are welcome!"* while GitHub was retired and `git.ullrich.is` reports **"Registration is disabled"**. So an outsider could not fork, could not open a PR, and could not file an issue — and there was no `CONTRIBUTING.md` explaining any alternative. The project was promising something impossible, same class as the 404s fixed in #26. ## What this adds **Two real paths in**, rather than opening registration: 1. **Request an account** by email. After that everything works normally — fork, branch, PR, review, merge. Recommended for anything beyond a one-liner, since you get CI results and inline review. 2. **Email a patch** (`git format-patch`). Needs no account anywhere, and `git am` preserves the contributor as commit author, so authorship credit survives into the history. Filing an issue without an account is covered too — email it, and it gets filed with credit. **Explains *why* registration is closed**, so it reads as a decision rather than neglect: the instance shares a box with other services, and open signup would mean CI running unreviewed code from unknown branches on the same runners that build and deploy production. That's the real reason, and it's a more honest thing to say than "personal instance". **Sets previously-undocumented expectations:** - every `CI / *` check must pass (`main` is protected) - external contributions are **squash-merged**, and Forgejo signs the result with the instance key — so **contributors don't need GPG configured** - **no merge queue**, so a long-open branch wants a rebase before final review - larger changes start as an **OpenSpec proposal**, not as code - **non-goals are named**: zero data collection in the Planner, no tracking/analytics, data must stay exportable. A change that violates those gets declined however well written — better to say so before someone spends a weekend on it. Plus the conventions that actually trip people up: explicit `routes.ts` registration (fails as a 404, not a build error), i18n for all user-facing strings, co-located tests, new packages needing both Dockerfiles. There's also a short, plain note that most of the codebase is AI-authored — because it changes what's *useful* to contribute. Design judgement, real-world testing, and "does this feature earn its complexity" are worth more here than volume of code. ## Verified rather than asserted A contribution guide that lies is worse than none, so every factual claim was checked: | claim | result | |---|---| | anonymous clone over HTTPS works | OK — cloned at `18560b3` with `GIT_TERMINAL_PROMPT=0` | | issue tracker publicly viewable | 200 | | all 8 linked paths exist | OK | | both `app/routes.ts` exist | OK | | all 6 referenced pnpm scripts exist | OK | | `main` requires `CI / *` | confirmed via branch protection API | Also drops a stale *"public **GitHub** issue"* line in `SECURITY.md` that the #26 sweep missed. ## Two things needing you 1. **`contribute@trails.cool` must exist** as a mailbox or alias. It's the one claim I couldn't verify, and the whole document routes through it — if you'd rather use a different address, it's a one-line change in three places. 2. **Unverified mechanic worth a real test if you ever open registration:** whether `require_signed_commits` rejects a PR whose *own* commits are unsigned. Squash-merging sidesteps it (the single landed commit is instance-signed), which is why the doc specifies squash for external contributions — but if you ever accept merge commits from contributors, that needs testing with a throwaway account first, because getting it wrong blocks the merge entirely.
docs: describe how contribution actually works
All checks were successful
CI / Dockerfile Package Check (pull_request) Successful in 20s
CI / Security Scan (pull_request) Successful in 56s
CI / Checks (pull_request) Successful in 3m6s
CI / Visual Tests (pull_request) Successful in 3m2s
CI / Journal Image Smoke Test (pull_request) Successful in 4m14s
CI / E2E Tests (pull_request) Successful in 6m3s
d1325cf26e
The README said "Human contributions are welcome!" while GitHub was retired
and git.ullrich.is reports "Registration is disabled". An outside contributor
could not fork, could not open a pull request, and could not file an issue.
The project was promising something impossible, and there was no
CONTRIBUTING.md to explain the real path.

This documents the path that exists rather than opening registration. Two
routes in, both real:

  1. Request an account by email. Fast, and after that everything works the
     normal way: fork, branch, PR, review, merge.
  2. Email a `git format-patch` patch. Needs no account anywhere, and `git am`
     preserves the contributor as commit author so authorship credit survives.

Also explains *why* registration is closed rather than leaving it looking like
neglect: the instance shares a box with other services, and open signup would
mean CI running unreviewed code from unknown branches on the same runners that
build and deploy production.

Sets expectations that were previously undocumented: every `CI / *` check must
pass, external contributions are squash-merged and Forgejo signs the result
with the instance key (so contributors do not need GPG configured), there is no
merge queue so stale branches want a rebase, and larger changes start as an
OpenSpec proposal rather than as code. Names the non-goals too — zero data
collection in the Planner, no tracking, exportable data — since those decline a
change regardless of how well it is written.

Claims verified rather than asserted: anonymous clone over HTTPS works, the
issue tracker is publicly viewable (200), all eight linked paths exist, both
`app/routes.ts` files exist, and all six referenced pnpm scripts exist.

Also drops a stale "GitHub issue" reference in SECURITY.md, missed in the
earlier GitHub-retirement sweep.

Note: `contribute@trails.cool` must exist as a mailbox or alias for this to be
true. That is the one thing here I could not verify myself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X8hNxgYp777FRqYtVmQNaU
ullrich deleted branch docs/contributing 2026-07-27 21:28:49 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
trails-cool/trails!30
No description provided.