Hedronite Lesson · Polyglot-Dev / V · Wed 2026-10-07 · V row #7 (Duha 2 of 4)

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.

Lesson Class: Duha (V dual-seat · learn-first · contributor-aware · watch-not-adopt)
Focus: Climb in Order · Filter Before You Pick · Format Before Commit · Test the Narrow Ring
Done-criteria: CONTRIBUTING ladder summarized; likes + labels filter shown (no 'good first issue' label in the guide); v fmt -w on a scratch file; scoped v test; pre-commit hook path named
Grounding: vlang/v 0.5.2 (7647ce1) CONTRIBUTING + TESTS.md + docs.md (Testing, v fmt) + git_pre_commit_hook.vsh; live tracker probe labelled as live
Note: Lab Mac, macOS 27.0.1 Apple M4 · fmt -w 0.01 s, 18 lines changed · v test . 1 passed · vlib/strings 0.65 s cc vs 0.48 s tcc · hook commit formatted · Nix Beat B skipped
Climb in Order
Starting 0–6, Medium 7–9, Advanced 10 (RFCs). Reproduce and review before the first code PR.
Filter Before You Pick
Likes filter: 22 open. Bug + Status: Confirmed: 0 open today (live). Guide names no good-first label.
Format Before Commit
cp cmd/tools/git_pre_commit_hook.vsh .git/hooks/pre-commit; v must be on PATH.
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

  1. 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.
  2. Filter Before You Pick. The guide gives two filters, by likes and by labels. Run both and read what comes back before choosing anything.
  3. Format Before Commit. v fmt -w rewrites the file in place. The pre-commit hook runs it for you on every staged .v file.
  4. Test the Narrow Ring. v test . on the code you touched, then a scoped vlib folder, then v test-all only when the patch is ready.

§III. The ladder

CONTRIBUTING has three rungs.

RungStepsWhat the guide asks
Starting0 to 6v 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 9bug-fix PRs for issues found in 1..6; suggest features or tools; implement suggestions
Advanced (after 1..9 "for a while")10work 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):

ProbeResult
Bug, OS: Mac, OS: Linux, OS: Windows, Status: Confirmedall exist
Feature Request404; the live label is Feature/Enhancement Request
Good First Issue (easy task)exists, 32 issues ever, 0 open
open issues, sorted by likes22; top is #29360 (vpm version ranges), 3 likes
guide's Windows label filter, open0
Bug + Status: Confirmed, open / all time0 / 978
open PRs19

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 ||.

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/.

RunResultreal
default C compiler (clang on macOS)5 passed, 4 skipped (.js.v), exit 00.65 s
-cc tcc5 passed, 4 skipped, exit 00.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

  1. Confirm git describe --tags prints 0.5.2; grep CONTRIBUTING for good first (0) and for the hook lines (132, 261).
  2. Write a badly formatted module; run v fmt -c, -verify, -w, then -verify again; keep the diff.
  3. v test . and v -stats test . in the module.
  4. VTEST_HIDE_OK=1 v test vlib/strings/, then again with -cc tcc.
  5. 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

  1. Searching for a "good first issue" label the guide never names, and missing that the live one is 0 open.
  2. Pasting label:"Feature Request" from the guide; it no longer resolves.
  3. Installing the hook while v is off PATH; the shebang then fails.
  4. Running v test-all as 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.