Read the V contributor ladder at 0.5.2: issue filters, v fmt -w, v test, and the pre-commit hook · Climb in Order · Filter Before You Pick · Format Before Commit · Test the Narrow Ring
Climb in order. Filter before you pick. Format before you commit. Test the narrow ring first.
Climb in order. Filter before you pick. Format before you commit. Test the narrow ring first.
§I. Frame
Duha V session 2 of 4 (syllabus row #7), Wed 2026-10-07. Learn-first, contributor-aware, watch-not-adopt. Yesterday built V 0.5.2 from the tag on the lab Mac and mapped the tree. Today reads the project's rules for helping, then runs three local checks: format, test, hook. Every cite is vlang/v at tag 0.5.2 (commit 7647ce1), read with git show 0.5.2: from the lab Mac checkout. One section uses live tracker data; it is marked as live.
§II. Four techniques
- Climb in Order. CONTRIBUTING numbers its tasks 0 to 10 and says they are "ordered in terms of easiness/time/nerves investment". Start at the bottom.
- Filter Before You Pick. The guide gives two filters, by likes and by labels. Run both and read what comes back before choosing anything.
- Format Before Commit.
v fmt -wrewrites the file in place. The pre-commit hook runs it for you on every staged.vfile. - Test the Narrow Ring.
v test .on the code you touched, then a scopedvlibfolder, thenv test-allonly when the patch is ready.
§III. The ladder
CONTRIBUTING has three rungs.
| Rung | Steps | What the guide asks |
|---|---|---|
| Starting | 0 to 6 | v quest for XP; read the docs and module docs; fix doc errors in PRs; write V programs or help others; read new issues; reproduce them and comment; read PRs and comment |
| Medium (after 1..6) | 7 to 9 | bug-fix PRs for issues found in 1..6; suggest features or tools; implement suggestions |
| Advanced (after 1..9 "for a while") | 10 | work on V RFCs in vlang/rfcs |
Read the gates. Medium opens only "after gathering experience with 1..6", and every medium step cites the earlier ones. If you skip to step 7, then your first PR fixes a bug you never reproduced; thus the guide puts reproduction (step 5) and PR review (step 6) before any code PR. A doc fix (step 2) is the cheapest first PR.
The Example Workflow (credited to spytheman) is the mechanics under the ladder: fork, clone the main repo, add your fork as a remote named pullrequest, branch, v fmt -w, v check-md for changed Markdown, git push pullrequest, then open the PR in the web UI. Its stated point: "never directly push to the main V repository, only to your own fork." Tomorrow's row drafts that PR without opening it.
§IV. The issue filter
CONTRIBUTING does not name a "good first issue" label. grep -ci 'good first' on the file at the tag returns 0. What it gives is a likes filter and a labels filter:
is:open is:issue sort:reactions-+1-desc
is:open is:issue label:Bug label:"OS: Windows" label:"Status: Confirmed"
The common labels it lists are Bug, Feature Request, OS: Linux, OS: Windows, OS: Mac, and Status: Confirmed. A the lab Mac contributor swaps the OS label: label:Bug label:"OS: Mac" label:"Status: Confirmed".
Live check (GitHub REST API, fetched 2026-10-07 10:09 ET, not tag-pinned; full log in lab/tracker-2026-10-07.log):
| Probe | Result |
|---|---|
Bug, OS: Mac, OS: Linux, OS: Windows, Status: Confirmed | all exist |
Feature Request | 404; the live label is Feature/Enhancement Request |
Good First Issue (easy task) | exists, 32 issues ever, 0 open |
| open issues, sorted by likes | 22; top is #29360 (vpm version ranges), 3 likes |
| guide's Windows label filter, open | 0 |
Bug + Status: Confirmed, open / all time | 0 / 978 |
| open PRs | 19 |
The guide's label filter returns nothing today. The likes filter returns 22 issues. So on this tracker, today, the labelled queue is empty and the open entry points are steps 4 to 6: read the 22 issues, reproduce one on macOS, review one of the 19 open PRs. The label names drift, too: the guide's Feature Request no longer resolves. Check label names on the live labels page before pasting a filter.
§V. Format before commit
docs.md says "Always run v fmt -w file.v before pushing your code" and calls a vfmt run "usually pretty cheap (takes <30ms)". The second line is an author claim; the lab measured one file.
The lab module ladder/ladder.v holds the ladder as a const array, a tier(n) function, and a step(n) !string that returns an error past step 10. It was written badly on purpose: no blank lines, two-space and eight-space indents, no spaces around <= or ||.
v fmt -cprintedFile is not formattedand exited 2.v fmt -verifyexited 1.v fmt -wprintedReformatted fileand exited 0 inreal 0.01. A second run printedAlready formatted file.- The diff is 18 changed lines: blank lines after
moduleand between declarations, tabs for indents, spaces around operators, and the longconstwrapped onto tab-indented continuation lines. v fmt -verifythen exited 0 on both files.
One detail from the diff: vfmt kept if n < 0 || n >= steps.len { return error('no step ${n}') } on one line but split the if/else if chain in tier. A short single-statement if survives; a chain does not. Read the diff and do not assume.
§VI. Test the narrow ring
docs.md gives the two module commands: v test mymodule and v test ., which runs every _test.v below the folder. The lab test file is an internal test (module ladder), three test_ functions, one of them returning ! so step(7)! can fail the test by propagation.
OK 212.036 ms
Summary for all V _test.v files: 1 passed, 1 total. Elapsed time: 531 ms, on 1 job. Comptime: 317 ms. Runtime: 212 ms.
v -stats test . broke it down: 7 asserts across 3 functions, all OK, compiled at 109,592 vlines/s (35,124 lines including vlib). v test . -run-only test_step_result ran just one function.
TESTS.md opens with "TLDR: do run v test-all locally, after making your changes, and before submitting PRs." It also lists what test-all runs: test-cleancode, test-self, test-fmt, build-tools, build-examples, check-md -hide-warnings ., and v install nedpals.args. The checkout holds 3356 _test.v files under vlib, and the last step installs a module from the network. That is the right gate before a real PR and the wrong one for a lesson, so the lab ran a scoped ring instead: VTEST_HIDE_OK=1 v test vlib/strings/.
| Run | Result | real |
|---|---|---|
| default C compiler (clang on macOS) | 5 passed, 4 skipped (.js.v), exit 0 | 0.65 s |
-cc tcc | 5 passed, 4 skipped, exit 0 | 0.48 s |
TESTS.md advises -cc tcc because "TCC is much faster". On the lab Mac, for nine files, comptime fell from 2347 ms to 1472 ms. The tip holds here, on a small ring; the full suite was not timed.
§VII. The pre-commit hook
CONTRIBUTING step 3.1, quoted exactly:
cp cmd/tools/git_pre_commit_hook.vsh .git/hooks/pre-commit
chmod 755 .git/hooks/pre-commit
The source path is cmd/tools/git_pre_commit_hook.vsh; the installed path is .git/hooks/pre-commit, run from the repo root. The script reads git diff --cached --name-only for .v, .vsh, *.vv, skips _input.vv files, runs v fmt -w on the rest, and git adds them back. With git config --bool hooks.stopCommitOfNonVfmtedVFiles true it switches to v fmt -verify and blocks the commit instead. Its shebang is #!/usr/bin/env -S v ..., so v must be on PATH when git runs it.
The lab installed it in a scratch repo with no remote, staged the unformatted ladder.v, and committed with the build dir on PATH. The hook printed The V pre commit hook will format 1 V file(s), the commit exited 0, and the committed blob matched the v fmt -w output byte for byte.
§VIII. Lab
- Confirm
git describe --tagsprints0.5.2; grep CONTRIBUTING forgood first(0) and for the hook lines (132, 261). - Write a badly formatted module; run
v fmt -c,-verify,-w, then-verifyagain; keep the diff. v test .andv -stats test .in the module.VTEST_HIDE_OK=1 v test vlib/strings/, then again with-cc tcc.- Install the hook in a scratch repo and commit the unformatted file.
Evidence in lab/: lab.sh, lab.log, fmt.diff, before/ladder.v, ladder/ladder.v, ladder/ladder_test.v, vtest-strings-default.log, vtest-strings-tcc.log, tracker-2026-10-07.log.
§IX. Common mistakes
- Searching for a "good first issue" label the guide never names, and missing that the live one is 0 open.
- Pasting
label:"Feature Request"from the guide; it no longer resolves. - Installing the hook while
vis offPATH; the shebang then fails. - Running
v test-allas an inner loop. It is the final gate and it touches the network.
§X. Contributor-path takeaway
Install the hook first, so format can never be the reason a PR bounces. Then work the ladder from the bottom against the live tracker: today that means reproducing one of the 22 open issues on macOS and commenting with the v doctor table from row #6, not hunting a confirmed-bug label that has nothing open. Run v test on the touched folder with -cc tcc, and keep v test-all for the last step before a push to your own fork.
This is learn-first contributor practice. It is not Hedronite product adoption, and no upstream issue or PR was opened.
Related: ·
Climb in order. Filter before you pick. Format before you commit. Test the narrow ring first.