@@ -39,17 +39,73 @@ assert behavior directly against the symbol named by the test. A triplet named
3939` TestOptions_WithMaxTokens_Bad ` must invoke ` WithMaxTokens ` in its own body,
4040not route through a dispatcher helper.
4141
42+ ## Writing Tests, Examples & Benchmarks
43+
44+ Every source file ships three siblings — extend them, never create monolithic
45+ compliance files, versioned test files (` _v2 ` ), or ` ax7* ` files:
46+
47+ | Sibling of ` foo.go ` | Holds | Verified by |
48+ | ---------------------| -------| -------------|
49+ | ` foo_test.go ` | one ` Test<Symbol>_<Case> ` per exported symbol per variant | ` task test ` |
50+ | ` foo_example_test.go ` | one ` Example<Symbol> ` per symbol, with an ` // Output: ` block | ` task test ` (runs + diffs the output) |
51+ | ` foo_bench_test.go ` | one ` Benchmark<Symbol> ` per hot symbol | ` task bench ` |
52+
53+ ** Tests — name the symbol, exercise it directly.** A test asserts against the
54+ symbol its name claims: ` TestOptions_WithMaxTokens_Bad ` must call
55+ ` WithMaxTokens ` in its own body, not route through a dispatcher/table helper.
56+ A test that never names its symbol is fake coverage the audit flags. Write the
57+ AX-7 triplet for each symbol — ` _Good ` (valid input, happy path), ` _Bad `
58+ (invalid input is rejected), ` _Ugly ` (malformed / boundary / empty). Production
59+ functions that can fail return ` core.Result ` : the ` _Good ` test asserts ` r.OK `
60+ then reads ` r.Value ` ; the ` _Bad ` /` _Ugly ` tests assert ` !r.OK ` .
61+
62+ ** Examples are compiled documentation.** ` func ExampleWithMaxTokens() ` ends with
63+ a ` // Output: ` block so ` go test ` runs and diffs it — a stale example fails the
64+ build. Print with ` Println ` from ` dappco.re/go ` , never ` fmt.Println ` .
65+
66+ ** Benchmarks measure the load path.** Shape:
67+
68+ ``` go
69+ var sinkResult core.Result // package sink — stops the compiler eliding the call
70+
71+ func BenchmarkDiscover (b *testing .B ) {
72+ dir := writeFixtureModel (b) // setup OUTSIDE the timed loop
73+ b.ReportAllocs ()
74+ b.ResetTimer () // discount the setup
75+ for i := 0 ; i < b.N ; i++ {
76+ sinkResult = Discover (dir) // assign to the sink so it can't be optimised away
77+ }
78+ }
79+ ```
80+
81+ Read ** B/op as hard as allocs/op** — the biggest wins (whole-slice clones,
82+ full-file reads) leave allocs/op flat while B/op screams. allocs/op is only
83+ trustworthy at steady state, so ` task bench ` runs ` -benchtime=20x ` ; a cold
84+ 3-iteration number is inflated by setup.
85+
4286## Working Locally
4387
44- Use the same commands as the compliance brief before handing work back:
88+ Run the Taskfile gates before handing work back (portable lanes need no GPU;
89+ ` *:metal ` lanes need ` task metallib ` first):
90+
91+ ``` sh
92+ task qa # gofmt check + go vet + portable tests — the pre-handback gate
93+ task test # portable suite (default tags, runs anywhere)
94+ task test:metal # engine/metal suite (-tags metal_runtime; needs task metallib)
95+ task cover # coverage.out + total — must clear the 95% codecov target
96+ task bench # every benchmark with -benchmem (allocation regressions)
97+ ```
98+
99+ ` codecov.yml ` enforces ** 95%** on both the project and each patch, measured on
100+ the portable ` task cover ` profile (the surface a Linux CI compiles; engine/metal
101+ is Darwin-only and covered by ` task test:metal ` ).
102+
103+ For core/go idiom compliance specifically, the audit script is the work
104+ provider — a change is not complete until it reports ` verdict: COMPLIANT ` with
105+ every counter at zero:
45106
46107``` sh
47108GOWORK=off go mod tidy
48- GOWORK=off go vet ./...
49- GOWORK=off go test -count=1 ./...
50109gofmt -l .
51110bash /Users/snider/Code/core/go/tests/cli/v090-upgrade/audit.sh .
52111```
53-
54- The audit script is the work provider for compliance tasks. A change is not
55- complete until it reports ` verdict: COMPLIANT ` with every counter at zero.
0 commit comments