You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .github/instructions/go.instructions.md
+26-11Lines changed: 26 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -87,6 +87,8 @@ Repository defaults (unless the repository explicitly documents an alternative):
87
87
88
88
-[GO-LCL-013]`gofmt` is mandatory for formatting (zero-config, non-negotiable).
89
89
-[GO-LCL-014]`golangci-lint` is the mandatory meta-linter; configure `.golangci.yml` with a strict baseline.
90
+
-[GO-LCL-014a] Enable `depguard` for import-direction constraints (see [GO-CODE-009]).
91
+
-[GO-LCL-014b] Enable `gomodguard` for module allow/deny lists (see [GO-CODE-010]).
90
92
-[GO-LCL-015]`staticcheck` is **mandatory** for static analysis; run in CI as a blocking gate.
91
93
-[GO-LCL-016]`go test` with race detector (`-race`) for tests.
92
94
@@ -544,18 +546,31 @@ Per [constitution.md §7](../../.specify/memory/constitution.md#7-code-quality-g
544
546
-[GO-CODE-003] Avoid package names like `util`, `common`, `helpers`, `misc` — they become dumping grounds.
545
547
-[GO-CODE-004] Use `internal/` for code that should not be imported by other modules.
546
548
547
-
### 11.2 Naming conventions
549
+
### 11.2 Enforcing architectural boundaries with linter rules
550
+
551
+
When a specification or architecture decision imposes import-direction or dependency constraints, **express them as linter configuration rather than custom Go test code**. Linter rules run on every `make lint`, produce clear error messages, and require no custom test maintenance.
552
+
553
+
-[GO-CODE-009] Use `depguard` (in `.golangci.yml`) to enforce import restrictions between packages:
554
+
-[GO-CODE-009a] Define named rule groups scoping file patterns to allowed/denied import paths.
555
+
-[GO-CODE-009b] Include the requirement ID in the `desc` field so failures are self-documenting.
556
+
-[GO-CODE-009c] Typical patterns: pipeline isolation (no concrete rule/formatter imports), rule isolation (no sibling rule imports), logger discipline (no stdlib `log` outside the logger package).
557
+
-[GO-CODE-010] Use `gomodguard` (in `.golangci.yml`) to enforce module-level bans:
558
+
-[GO-CODE-010a] Block deprecated or banned modules with a `reason` referencing the requirement ID.
559
+
-[GO-CODE-010b] Use for non-goal enforcement (e.g. banning AI/NLP libraries from an MVP).
560
+
-[GO-CODE-011]**Only use custom Go architecture tests** (AST scanning, `go/packages`) for constraints that linter rules cannot express: call-order verification, banned function-call patterns within a package, interface signature checks, or cross-file structural invariants.
561
+
562
+
### 11.3 Naming conventions
548
563
549
564
-[GO-CODE-005] Use **MixedCaps** (exported) and **mixedCaps** (unexported). Do not use underscores in Go names.
550
565
-[GO-CODE-006] Prefer short, descriptive names. In Go: `i` for loop index, `r` for reader, `w` for writer, `ctx` for context, `err` for error.
551
566
-[GO-CODE-007] Avoid stuttering: `user.User` is fine, but `user.UserService` in package `user` should just be `Service`.
552
567
-[GO-CODE-008] Acronyms should be all caps: `HTTP`, `URL`, `ID`, not `Http`, `Url`, `Id`.
553
568
554
-
### 11.3 Struct organisation
569
+
### 11.4 Struct organisation
555
570
556
-
-[GO-CODE-009] Group struct fields logically. Put related fields together.
557
-
-[GO-CODE-010] Order fields to minimise padding (largest alignment first), or use `fieldalignment` linter.
558
-
-[GO-CODE-011]**Start enums at one, not zero**, unless zero has explicit meaning:
571
+
-[GO-CODE-012] Group struct fields logically. Put related fields together.
572
+
-[GO-CODE-013] Order fields to minimise padding (largest alignment first), or use `fieldalignment` linter.
573
+
-[GO-CODE-014]**Start enums at one, not zero**, unless zero has explicit meaning:
559
574
560
575
```go
561
576
typeStatusint
@@ -570,9 +585,9 @@ Per [constitution.md §7](../../.specify/memory/constitution.md#7-code-quality-g
570
585
571
586
This ensures uninitialized values are distinguishable from valid values.
572
587
573
-
### 11.4 Time handling
588
+
### 11.5 Time handling
574
589
575
-
-[GO-CODE-012]**Always use `time.Duration` for time periods**, never raw integers:
590
+
-[GO-CODE-015]**Always use `time.Duration` for time periods**, never raw integers:
576
591
577
592
```go
578
593
// Good
@@ -582,8 +597,8 @@ Per [constitution.md §7](../../.specify/memory/constitution.md#7-code-quality-g
582
597
func Retry(attempts int, delay int) error
583
598
```
584
599
585
-
- [GO-CODE-013] Store and transmit times in UTC. Convert to local time only for display.
586
-
- [GO-CODE-014] Use `time.Time` for timestamps, not Unix epoch integers.
600
+
- [GO-CODE-016] Store and transmit times in UTC. Convert to local time only for display.
601
+
- [GO-CODE-017] Use `time.Time` for timestamps, not Unix epoch integers.
587
602
588
603
---
589
604
@@ -838,5 +853,5 @@ These patterns cause recurring issues in Go codebases. Avoid them unless an ADR
Copy file name to clipboardExpand all lines: .github/instructions/includes/quality-gates-baseline.include.md
+11-2Lines changed: 11 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,7 +16,16 @@ Use this shared baseline for quality gate execution expectations. Domain-specifi
16
16
-[QG-BASE-DEF-001] Iterate until all checks complete with **no errors or warnings**.
17
17
-[QG-BASE-DEF-002] Treat warnings as defects unless explicitly waived in an ADR (with rationale and expiry).
18
18
19
+
## 3. Mechanism selection 🎯
20
+
21
+
When a specification or architecture decision imposes a constraint (e.g. "package X must not import package Y", "banned dependency Z"), choose the lightest enforcement mechanism that provides full confidence:
22
+
23
+
-[QG-BASE-MECH-001]**Linter configuration first.** If the constraint can be expressed as a linter rule (import restrictions, module bans, naming conventions), implement it as linter config. Linter rules run automatically on every `make lint`, produce clear error messages, and need no custom test maintenance.
24
+
-[QG-BASE-MECH-002]**Architecture tests second.** Use custom test code (AST scanning, dependency graph analysis) only for constraints that linter rules cannot express: call-order verification, banned function-call patterns within a package, interface signature checks, or cross-file structural invariants.
25
+
-[QG-BASE-MECH-003]**Integration/behavioural tests for product behaviour.** Use integration tests for constraints that require running the compiled artefact: CLI exit codes, output formats, error recovery, performance thresholds.
26
+
-[QG-BASE-MECH-004]**Do not double up.** If a constraint is enforced by linter config, do not also write a Go test for the same constraint. One mechanism per constraint.
0 commit comments