From f6b1ba99857e542ec987c916e5e2781e93470785 Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Mon, 24 Aug 2026 15:01:51 +0200 Subject: [PATCH] doc: restyled comments Signed-off-by: Frederic BIDON --- .claude/rules/technical-writing.md | 67 ++++++++++++++++++++++++++++++ object_validator.go | 2 +- path.go | 2 +- pools.go | 2 +- spec.go | 2 +- 5 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 .claude/rules/technical-writing.md diff --git a/.claude/rules/technical-writing.md b/.claude/rules/technical-writing.md new file mode 100644 index 0000000..3f0ae36 --- /dev/null +++ b/.claude/rules/technical-writing.md @@ -0,0 +1,67 @@ +--- +paths: + - "**/*.go" + - "**/*.md" +--- + +# Technical writing style (go-openapi) + +Applies to every committed comment, commit message, README and doc-site page. + +The standard is Ernest Gowers, *Plain Words*: **be short, be simple, be human.** +His worked example is the whole rule: + + DON'T Was this the realisation of an anticipated liability? + DO Did you expect to have to do this? + +The abstract nouns carry no information; the concrete verb carries all of it. + +## Two tests + +**The grep test.** Does the sentence contain something a reader can search for — an +identifier, a file, a flag, an error, a number with a unit? Prose that names nothing has +described the code without pointing at it. + +**The quotability test.** A sentence that would survive being quoted on its own is too +pleased with itself. Rewrite it until it merely sounds true. + +## Never define by inversion + +The worst and most frequent fault. A copula whose subject or predicate is a wh-clause +promises a definition and delivers a metaphor. Both directions are banned: + + DON'T Coverage is what says which templates a suite never reaches. + DON'T What is lost is the doc comment. + DO Coverage records which templates the suite never executed. + DO A synthesized type loses its doc comment. + +The rewrite is mechanical: find the verb hiding inside the wh-clause and make it the main +verb of the sentence. + +`which is why` pointing back at a fact just stated is legitimate, and rationed — one per +comment is plenty. + +## The rest + +- **Name the thing.** `WithRoots`, not "the option that scopes a repository". Name the + error, the file, the flag, the upstream package, the constant. +- **Statement, not aphorism.** State mechanism and effect. Never close a paragraph on a + maxim: the reflex lands hardest on a closing sentence. +- **Keep a subject.** "New returns an error if the source is unreadable", not "What a + source leaves out is settled where it is declared". +- **Plain verbs.** add, fix, return, parse, reject, cap, prune, record. Code does not say, + judge, grant, refuse, know, mean to, or reach for. `report` is fine when something + genuinely reports. +- **Keep the numbers.** Sizes with units, counts, ratios, advisory ids. `286 -> 178 KiB`, + `GHSA-v2xp-g8xf-22pf`. Dropping them for a smoother sentence loses information. +- **Be human.** Address the reader where there is advice: "Use `WithRoot` to confine local + loading." Admit the awkward thing rather than smoothing it over. + +## Self-check + + # definition by inversion, both directions + grep -rnE '\b(is|are) (what|where) [a-z]' --include='*.go' --include='*.md' . + grep -rnE '(^|\. )What [a-z][a-z ,-]{3,50} (is|are) ' --include='*.go' --include='*.md' . + +Subtract the legitimate `which/that/this/it is what` before judging the first one. +Neither grep is a verdict — they find one fault out of six. The others need reading. diff --git a/object_validator.go b/object_validator.go index 4f1dd15..cac243e 100644 --- a/object_validator.go +++ b/object_validator.go @@ -375,7 +375,7 @@ func (o *objectValidator) validatePropertiesSchema(val map[string]any, res *Resu } // located on the object that lacks the property: the property itself - // has no node to point at, and the object is what has to be amended + // has no node to point at, and the object has to be amended res.addErrorsAt(o.Path, errors.Required(o.Path.child(k).dotted(), o.In, v)) } } diff --git a/path.go b/path.go index 940fc4b..4b2da25 100644 --- a/path.go +++ b/path.go @@ -16,7 +16,7 @@ import ( // // Validators build a location by appending tokens as they descend into // properties and array items, then render it only when they report an error. -// Keeping the tokens apart until then is what makes it possible to produce a +// Keeping the tokens apart until then makes it possible to produce a // valid [RFC 6901] JSON pointer: a token is escaped when it is rendered, and // the separator can never be confused with a token that contains one. // diff --git a/pools.go b/pools.go index 0bc95d1..24fde6e 100644 --- a/pools.go +++ b/pools.go @@ -12,7 +12,7 @@ import ( // // Validation allocates a validator per schema node and a result per check, so // the same handful of types are built and thrown away constantly. Recycling -// them is what keeps validating a large specification affordable. +// them keeps validating a large specification affordable. // // Build with the "poolsdebug" tag to have every borrow and redeem tracked: // misuse then panics where it happens rather than corrupting a pool, and diff --git a/spec.go b/spec.go index e5d16b6..0dc0dd3 100644 --- a/spec.go +++ b/spec.go @@ -190,7 +190,7 @@ func (s *SpecValidator) SetContinueOnErrors(c bool) { func (s *SpecValidator) validateNonEmptyPathParamNames() *Result { res := validatorPools.results.Borrow() if s.spec.Spec().Paths == nil { - // There is no Paths object: the document itself is what lacks it, so + // There is no Paths object: the document itself lacks it, so // there is no node below it to point at res.addErrorsAt(rootPath(), noValidPathMsg())