lgtm-specs 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +14 -0
- package/.gemini/README.md +8 -0
- package/.gemini/config.yaml +20 -0
- package/.gemini/styleguide.md +35 -0
- package/.github/workflows/README.md +5 -0
- package/.github/workflows/release.yml +52 -0
- package/.github/workflows/validate.yml +27 -0
- package/.prettierignore +4 -0
- package/.prettierrc +1 -0
- package/AGENTS.md +151 -0
- package/README.md +98 -0
- package/VERSION +1 -0
- package/agents/README.md +73 -0
- package/agents/modes/README.md +9 -0
- package/agents/modes/build.md +88 -0
- package/agents/modes/hack.md +76 -0
- package/agents/modes/review.md +79 -0
- package/agents/roles/builder.md +75 -0
- package/agents/roles/counsel.md +96 -0
- package/agents/roles/explorer.md +77 -0
- package/agents/roles/lead.md +76 -0
- package/agents/roles/librarian.md +63 -0
- package/agents/roles/planner.md +75 -0
- package/agents/roles/reviewer/BASE.md +9 -0
- package/agents/roles/reviewer/OUTPUT_FORMAT.md +4 -0
- package/agents/roles/reviewer/README.md +48 -0
- package/agents/roles/reviewer/lite.md +51 -0
- package/agents/roles/reviewer/logic.md +48 -0
- package/agents/roles/reviewer/performance.md +45 -0
- package/agents/roles/reviewer/plan.md +52 -0
- package/agents/roles/reviewer/quality.md +49 -0
- package/agents/roles/reviewer/security.md +47 -0
- package/agents/roles/reviewer/test.md +48 -0
- package/agents/templates/README.md +6 -0
- package/agents/templates/mode.md +33 -0
- package/agents/templates/role.md +73 -0
- package/contribute/README.md +24 -0
- package/contribute/add-agent.md +29 -0
- package/contribute/add-ci.md +31 -0
- package/contribute/add-constitution.md +17 -0
- package/contribute/add-law.md +20 -0
- package/contribute/add-policy.md +27 -0
- package/contribute/checklist.md +42 -0
- package/contribute/maintenance.md +19 -0
- package/contribute/update-models.md +47 -0
- package/docs/README.md +13 -0
- package/docs/adr/0001-knowledge-engineering-workflow.md +22 -0
- package/docs/adr/0002-rule-hierarchy.md +25 -0
- package/docs/adr/0003-atomic-knowledge-graph.md +21 -0
- package/docs/adr/0004-identification-schema.md +22 -0
- package/docs/adr/0005-agent-specialization.md +39 -0
- package/docs/adr/0006-git-workflow-integrity.md +34 -0
- package/docs/adr/0007-operating-modes-and-gates.md +54 -0
- package/docs/adr/0008-rules-vs-workflows-boundary.md +64 -0
- package/docs/adr/README.md +14 -0
- package/docs/agent_architecture.md +164 -0
- package/docs/context_lifecycle.md +228 -0
- package/docs/engineering_principles.md +128 -0
- package/docs/local_policies.md +59 -0
- package/docs/meta/collaborative_dynamics.md +142 -0
- package/docs/meta/domains/README.md +8 -0
- package/docs/meta/domains/bitcoin/01-units.md +21 -0
- package/docs/meta/domains/bitcoin/02-broadcast-cancellation.md +20 -0
- package/docs/meta/domains/bitcoin/03-fee-rates-rounding.md +21 -0
- package/docs/meta/domains/bitcoin/04-confirmations-reorgs.md +20 -0
- package/docs/meta/domains/bitcoin/05-address-gap-limit.md +16 -0
- package/docs/meta/domains/bitcoin/06-relay-policy.md +27 -0
- package/docs/meta/domains/bitcoin/README.md +12 -0
- package/docs/meta/domains/git/01-workflow.md +89 -0
- package/docs/meta/domains/git/02-commits.md +57 -0
- package/docs/meta/domains/git/03-collaboration.md +40 -0
- package/docs/meta/domains/git/04-integrity.md +26 -0
- package/docs/meta/domains/git/05-configuration.md +209 -0
- package/docs/meta/domains/git/06-advanced.md +130 -0
- package/docs/meta/domains/git/README.md +29 -0
- package/docs/meta/industry_best_practices.md +555 -0
- package/docs/meta/languages/README.md +8 -0
- package/docs/meta/languages/go/01-concurrency.md +37 -0
- package/docs/meta/languages/go/02-api-design.md +30 -0
- package/docs/meta/languages/go/03-resilience.md +27 -0
- package/docs/meta/languages/go/04-errors.md +27 -0
- package/docs/meta/languages/go/05-performance.md +18 -0
- package/docs/meta/languages/go/06-safety.md +18 -0
- package/docs/meta/languages/go/07-testing.md +44 -0
- package/docs/meta/languages/go/08-config-layout.md +23 -0
- package/docs/meta/languages/go/README.md +14 -0
- package/docs/meta/languages/typescript/01-strictness.md +19 -0
- package/docs/meta/languages/typescript/02-immutability.md +15 -0
- package/docs/meta/languages/typescript/03-async.md +18 -0
- package/docs/meta/languages/typescript/04-design.md +19 -0
- package/docs/meta/languages/typescript/05-control-flow.md +11 -0
- package/docs/meta/languages/typescript/README.md +11 -0
- package/docs/meta/workflow.md +68 -0
- package/docs/philosophy.md +36 -0
- package/integrate/README.md +459 -0
- package/integrate/versioning.md +41 -0
- package/models/README.md +68 -0
- package/models/registry.yaml +55 -0
- package/package.json +11 -0
- package/rules/README.md +57 -0
- package/rules/RULE-00000-EXAMPLE.md +29 -0
- package/rules/constitution/CONS-00001-srp.md +40 -0
- package/rules/constitution/CONS-00002-ocp.md +43 -0
- package/rules/constitution/CONS-00003-lsp.md +44 -0
- package/rules/constitution/CONS-00004-isp.md +46 -0
- package/rules/constitution/CONS-00005-dip.md +37 -0
- package/rules/constitution/CONS-00006-dry.md +45 -0
- package/rules/constitution/CONS-00007-demeter.md +35 -0
- package/rules/constitution/CONS-00008-composition.md +44 -0
- package/rules/constitution/CONS-00009-deep-modules.md +39 -0
- package/rules/constitution/CONS-00010-kiss.md +47 -0
- package/rules/constitution/CONS-00011-yagni.md +49 -0
- package/rules/constitution/CONS-00012-cognitive-limits.md +28 -0
- package/rules/constitution/CONS-00013-boy-scout.md +27 -0
- package/rules/constitution/CONS-00014-broken-windows.md +35 -0
- package/rules/constitution/CONS-00015-safety.md +46 -0
- package/rules/constitution/CONS-00016-cqs.md +39 -0
- package/rules/constitution/CONS-00017-postel.md +35 -0
- package/rules/constitution/CONS-00018-cap.md +35 -0
- package/rules/constitution/CONS-00019-fallacies.md +37 -0
- package/rules/constitution/CONS-00020-shift-left.md +28 -0
- package/rules/constitution/CONS-00021-congruence.md +28 -0
- package/rules/constitution/CONS-00022-orthogonality.md +40 -0
- package/rules/constitution/CONS-00023-determinism.md +38 -0
- package/rules/constitution/CONS-00024-security.md +42 -0
- package/rules/constitution/CONS-00025-efficiency.md +38 -0
- package/rules/constitution/CONS-00026-resilience.md +41 -0
- package/rules/constitution/CONS-00027-transparency.md +40 -0
- package/rules/constitution/CONS-00028-evolvability.md +36 -0
- package/rules/constitution/CONS-00029-operability.md +36 -0
- package/rules/constitution/CONS-00030-rework-cycle.md +27 -0
- package/rules/constitution/CONS-00031-checklist.md +28 -0
- package/rules/constitution/CONS-00032-documentation.md +39 -0
- package/rules/constitution/README.md +52 -0
- package/rules/laws/README.md +15 -0
- package/rules/laws/bitcoin/BTC-00001-amounts-as-satoshis.md +39 -0
- package/rules/laws/bitcoin/BTC-00002-broadcast-not-cancelable.md +36 -0
- package/rules/laws/bitcoin/BTC-00003-fee-rate-math-rounding.md +37 -0
- package/rules/laws/bitcoin/BTC-00004-confirmations-and-reorgs.md +40 -0
- package/rules/laws/bitcoin/BTC-00005-address-gap-limit.md +37 -0
- package/rules/laws/bitcoin/BTC-00006-relay-is-policy-dependent.md +36 -0
- package/rules/laws/bitcoin/BTC-00007-dust-policy.md +36 -0
- package/rules/laws/bitcoin/BTC-00008-min-relay-fee.md +36 -0
- package/rules/laws/bitcoin/BTC-00009-feefilter.md +36 -0
- package/rules/laws/bitcoin/README.md +29 -0
- package/rules/laws/default.md +30 -0
- package/rules/laws/git/GIT-00001-atomic-commit.md +29 -0
- package/rules/laws/git/GIT-00002-imperative-subject.md +27 -0
- package/rules/laws/git/GIT-00003-formatting-50-72.md +28 -0
- package/rules/laws/git/GIT-00004-trunk-based.md +28 -0
- package/rules/laws/git/GIT-00005-public-immutability.md +26 -0
- package/rules/laws/git/GIT-00006-signing.md +27 -0
- package/rules/laws/git/GIT-00007-reviewer-capital.md +26 -0
- package/rules/laws/git/GIT-00008-patch-series.md +28 -0
- package/rules/laws/git/GIT-00009-branch-naming.md +28 -0
- package/rules/laws/git/GIT-00010-pr-hygiene.md +51 -0
- package/rules/laws/git/GIT-00011-merge-method.md +35 -0
- package/rules/laws/git/GIT-00012-conflict-resolution.md +35 -0
- package/rules/laws/git/GIT-00013-ignore-standards.md +38 -0
- package/rules/laws/git/GIT-00014-lfs-large-binaries.md +37 -0
- package/rules/laws/git/GIT-00015-git-hooks.md +35 -0
- package/rules/laws/git/GIT-00016-branch-protection.md +34 -0
- package/rules/laws/git/GIT-00017-secrets-management.md +34 -0
- package/rules/laws/git/GIT-00018-ci-enforcement.md +33 -0
- package/rules/laws/git/GIT-00019-review-checklist.md +39 -0
- package/rules/laws/git/GIT-00020-issue-references.md +34 -0
- package/rules/laws/git/GIT-00021-partial-staging.md +38 -0
- package/rules/laws/git/GIT-00022-feature-flags.md +33 -0
- package/rules/laws/git/GIT-00023-breaking-changes.md +41 -0
- package/rules/laws/git/GIT-00024-dependency-management.md +44 -0
- package/rules/laws/git/GIT-00025-large-repository-optimization.md +54 -0
- package/rules/laws/git/README.md +31 -0
- package/rules/laws/go/GO-00001-actor-model.md +51 -0
- package/rules/laws/go/GO-00002-api-design.md +37 -0
- package/rules/laws/go/GO-00003-error-handling.md +43 -0
- package/rules/laws/go/GO-00004-context.md +45 -0
- package/rules/laws/go/GO-00005-performance.md +40 -0
- package/rules/laws/go/GO-00006-packages.md +29 -0
- package/rules/laws/go/GO-00007-circuit-breakers.md +43 -0
- package/rules/laws/go/GO-00008-safety.md +39 -0
- package/rules/laws/go/GO-00009-table-driven-test.md +48 -0
- package/rules/laws/go/GO-00010-escape-analysis.md +37 -0
- package/rules/laws/go/GO-00011-retry.md +45 -0
- package/rules/laws/go/GO-00012-rate-limiting.md +42 -0
- package/rules/laws/go/GO-00013-io-buffering.md +43 -0
- package/rules/laws/go/GO-00014-memory-layout.md +41 -0
- package/rules/laws/go/GO-00015-aaa-pattern.md +49 -0
- package/rules/laws/go/GO-00016-test-libraries.md +35 -0
- package/rules/laws/go/GO-00017-comments.md +37 -0
- package/rules/laws/go/GO-00018-test-isolation.md +38 -0
- package/rules/laws/go/GO-00019-test-comments.md +36 -0
- package/rules/laws/go/GO-00020-mocking.md +36 -0
- package/rules/laws/go/GO-00021-configuration.md +36 -0
- package/rules/laws/go/GO-00022-observability.md +34 -0
- package/rules/laws/go/GO-00023-dependency-management.md +28 -0
- package/rules/laws/go/GO-00024-project-layout.md +30 -0
- package/rules/laws/go/GO-00025-concurrency-patterns.md +39 -0
- package/rules/laws/go/README.md +45 -0
- package/rules/laws/typescript/README.md +14 -0
- package/rules/laws/typescript/TS-00001-no-any.md +39 -0
- package/rules/laws/typescript/TS-00002-immutability.md +36 -0
- package/rules/laws/typescript/TS-00003-async.md +35 -0
- package/rules/laws/typescript/TS-00004-strict-null.md +38 -0
- package/rules/laws/typescript/TS-00005-unions.md +35 -0
- package/rules/laws/typescript/TS-00006-interface.md +38 -0
- package/rules/laws/typescript/TS-00007-generics.md +38 -0
- package/rules/laws/typescript/TS-00008-modules.md +28 -0
- package/rules/policies/README.md +12 -0
- package/rules/policies/default.md +28 -0
- package/scripts/README.md +45 -0
- package/scripts/generate_release_notes.py +376 -0
- package/scripts/validate_specs.py +730 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# The Law of Git
|
|
2
|
+
|
|
3
|
+
These rules define the rigorous communication protocol for Git version control.
|
|
4
|
+
|
|
5
|
+
## Index
|
|
6
|
+
|
|
7
|
+
- [GIT-00001: The Atomic Commit](GIT-00001-atomic-commit.md)
|
|
8
|
+
- [GIT-00002: The Imperative Subject](GIT-00002-imperative-subject.md)
|
|
9
|
+
- [GIT-00003: The 50/72 Rule](GIT-00003-formatting-50-72.md)
|
|
10
|
+
- [GIT-00004: Trunk-Based Flow](GIT-00004-trunk-based.md)
|
|
11
|
+
- [GIT-00005: Public History Immutability](GIT-00005-public-immutability.md)
|
|
12
|
+
- [GIT-00006: Cryptographic Identity](GIT-00006-signing.md)
|
|
13
|
+
- [GIT-00007: Reviewer Capital](GIT-00007-reviewer-capital.md)
|
|
14
|
+
- [GIT-00008: Logical Commit Series Structure](GIT-00008-patch-series.md)
|
|
15
|
+
- [GIT-00009: Branch Naming](GIT-00009-branch-naming.md)
|
|
16
|
+
- [GIT-00010: Pull Request Hygiene](GIT-00010-pr-hygiene.md)
|
|
17
|
+
- [GIT-00011: Merge Method (No Squash)](GIT-00011-merge-method.md)
|
|
18
|
+
- [GIT-00012: Conflict Resolution](GIT-00012-conflict-resolution.md)
|
|
19
|
+
- [GIT-00013: Ignore Standards](GIT-00013-ignore-standards.md)
|
|
20
|
+
- [GIT-00014: Large Binaries via LFS](GIT-00014-lfs-large-binaries.md)
|
|
21
|
+
- [GIT-00015: Git Hooks as a Fast Gate](GIT-00015-git-hooks.md)
|
|
22
|
+
- [GIT-00016: Branch Protection Policy](GIT-00016-branch-protection.md)
|
|
23
|
+
- [GIT-00017: Secrets Management](GIT-00017-secrets-management.md)
|
|
24
|
+
- [GIT-00018: CI Enforcement](GIT-00018-ci-enforcement.md)
|
|
25
|
+
- [GIT-00019: Code Review Checklist](GIT-00019-review-checklist.md)
|
|
26
|
+
- [GIT-00020: Issue Reference Standards](GIT-00020-issue-references.md)
|
|
27
|
+
- [GIT-00021: Partial Staging for Atomic Commits](GIT-00021-partial-staging.md)
|
|
28
|
+
- [GIT-00022: Feature Flags for Trunk Discipline](GIT-00022-feature-flags.md)
|
|
29
|
+
- [GIT-00023: Breaking Change Management](GIT-00023-breaking-changes.md)
|
|
30
|
+
- [GIT-00024: Dependency Management in Version Control](GIT-00024-dependency-management.md)
|
|
31
|
+
- [GIT-00025: Large Repository Optimization](GIT-00025-large-repository-optimization.md)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# The Actor Model (GO-00001)
|
|
2
|
+
|
|
3
|
+
**Source**: [btcwallet Engineering Guide](../../../docs/meta/languages/go/01-concurrency.md#concurrency-architecture-the-actor-model)
|
|
4
|
+
**Tags**: #structural #go #concurrency #actor-model
|
|
5
|
+
**Related**: [Safety](../../constitution/CONS-00015-safety.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
Do not communicate by sharing memory; instead, share memory by communicating.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **State Isolation**: An Actor (goroutine) owns its state exclusively.
|
|
14
|
+
2. **Message Passing**: Communicate only via channels.
|
|
15
|
+
3. **Lifecycle**: Never start a goroutine without a `select { case <-ctx.Done(): return }` loop.
|
|
16
|
+
|
|
17
|
+
## Anti-Patterns
|
|
18
|
+
|
|
19
|
+
- **Shared State**: Accessing a map from multiple goroutines without explicit locking (Race Condition).
|
|
20
|
+
- **Leakage**: Goroutines that run forever because they ignore cancellation.
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
**Bad:**
|
|
25
|
+
|
|
26
|
+
```go
|
|
27
|
+
// Race condition: 'counts' accessed by multiple workers without sync
|
|
28
|
+
func worker(counts map[string]int) {
|
|
29
|
+
counts["key"]++ // CRASH
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Good:**
|
|
34
|
+
|
|
35
|
+
```go
|
|
36
|
+
// Safe: State owned by single actor, updated via messages
|
|
37
|
+
func counterActor(ctx context.Context, updates <-chan string) {
|
|
38
|
+
counts := make(map[string]int)
|
|
39
|
+
for {
|
|
40
|
+
select {
|
|
41
|
+
case <-ctx.Done():
|
|
42
|
+
return
|
|
43
|
+
case u, ok := <-updates:
|
|
44
|
+
if !ok {
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
counts[u]++
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# API Design (GO-00002)
|
|
2
|
+
|
|
3
|
+
**Source**: [btcwallet Engineering Guide](../../../docs/meta/languages/go/02-api-design.md#2-interface-design)
|
|
4
|
+
**Tags**: #structural #go #interface #isp
|
|
5
|
+
**Related**: [ISP](../../constitution/CONS-00004-isp.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
Accept Interfaces, Return Structs.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **Consumer-Defined**: Interfaces should be defined where they are used, not where they are implemented.
|
|
14
|
+
2. **Concrete Returns**: Functions should return structs to allow future expansion (adding methods) without breaking callers.
|
|
15
|
+
|
|
16
|
+
## Anti-Patterns
|
|
17
|
+
|
|
18
|
+
- **Preemptive Interfaces**: Defining `IService` inside the `service` package that mirrors the struct methods exactly.
|
|
19
|
+
- **Returning Interfaces**: `func New() StoreInterface`. This locks the implementation and forces all callers to update if the interface changes.
|
|
20
|
+
|
|
21
|
+
## Examples
|
|
22
|
+
|
|
23
|
+
**Bad:**
|
|
24
|
+
|
|
25
|
+
```go
|
|
26
|
+
type Storer interface { Save() }
|
|
27
|
+
func NewStore() Storer { ... } // Returns interface
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Good:**
|
|
31
|
+
|
|
32
|
+
```go
|
|
33
|
+
func NewStore() *Store { ... } // Returns struct
|
|
34
|
+
// Interface defined by consumer:
|
|
35
|
+
type Saver interface { Save() }
|
|
36
|
+
func UseStore(s Saver) { ... }
|
|
37
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Error Handling (GO-00003)
|
|
2
|
+
|
|
3
|
+
**Source**: [btcwallet Engineering Guide](../../../docs/meta/languages/go/04-errors.md#error-handling)
|
|
4
|
+
**Tags**: #behavioral #go #errors #resilience
|
|
5
|
+
**Related**: [Transparency](../../constitution/CONS-00027-transparency.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
Errors are values and must be handled explicitly using modern Go patterns.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **Wrapping**: Use `fmt.Errorf("doing x: %w", err)` to add context.
|
|
14
|
+
2. **Checks**: Use `errors.Is(err, Target)` for sentinel checks. Never use `==`.
|
|
15
|
+
3. **Aggregation**: Use `errors.Join(err1, err2)` (Go 1.20+) for collecting errors (e.g., in defer cleanup).
|
|
16
|
+
|
|
17
|
+
## Anti-Patterns
|
|
18
|
+
|
|
19
|
+
- **Raw Returns**: Returning `err` without context (makes debugging impossible).
|
|
20
|
+
- **Type Assertions**: Using `err.(MyError)` without `errors.As`.
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
**Bad:**
|
|
25
|
+
|
|
26
|
+
```go
|
|
27
|
+
func Close() error {
|
|
28
|
+
err1 := f.Close()
|
|
29
|
+
err2 := net.Close()
|
|
30
|
+
if err1 != nil { return err1 } // Swallows err2
|
|
31
|
+
return err2
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Good:**
|
|
36
|
+
|
|
37
|
+
```go
|
|
38
|
+
func Close() error {
|
|
39
|
+
err1 := f.Close()
|
|
40
|
+
err2 := net.Close()
|
|
41
|
+
return errors.Join(err1, err2)
|
|
42
|
+
}
|
|
43
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Context Propagation (GO-00004)
|
|
2
|
+
|
|
3
|
+
**Source**: [btcwallet Engineering Guide](../../../docs/meta/languages/go/03-resilience.md#1-context-propagation-the-red-thread)
|
|
4
|
+
**Tags**: #runtime #go #concurrency #context
|
|
5
|
+
**Related**: [Resilience](../../constitution/CONS-00026-resilience.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
The `context.Context` is the "Red Thread" that binds a request's lifecycle.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **First Argument**: Every function doing I/O must accept `ctx context.Context` as the first arg.
|
|
14
|
+
2. **ErrGroup**: Use `golang.org/x/sync/errgroup` to manage groups of goroutines with shared cancellation.
|
|
15
|
+
3. **Respect**: Check `ctx.Err()` or `select <-ctx.Done()` before doing work.
|
|
16
|
+
|
|
17
|
+
## Anti-Patterns
|
|
18
|
+
|
|
19
|
+
- **Background**: Using `context.Background()` inside a request handler.
|
|
20
|
+
- **Unmanaged Goroutines**: `go func()` without a mechanism to cancel it via context.
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
**Bad:**
|
|
25
|
+
|
|
26
|
+
```go
|
|
27
|
+
go func() {
|
|
28
|
+
doWork() // No cancellation context
|
|
29
|
+
}()
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Good:**
|
|
33
|
+
|
|
34
|
+
```go
|
|
35
|
+
g, ctx := errgroup.WithContext(ctx)
|
|
36
|
+
g.Go(func() error {
|
|
37
|
+
return doWork(ctx)
|
|
38
|
+
})
|
|
39
|
+
g.Go(func() error {
|
|
40
|
+
return doOtherWork(ctx)
|
|
41
|
+
})
|
|
42
|
+
if err := g.Wait(); err != nil {
|
|
43
|
+
return fmt.Errorf("worker failed: %w", err)
|
|
44
|
+
}
|
|
45
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Runtime Performance (GO-00005)
|
|
2
|
+
|
|
3
|
+
**Source**: [btcwallet Engineering Guide](../../../docs/meta/languages/go/05-performance.md#performance--efficiency)
|
|
4
|
+
**Tags**: #runtime #go #performance #efficiency
|
|
5
|
+
**Related**: [Efficiency](../../constitution/CONS-00025-efficiency.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
Optimize for the Runtime (Garbage Collector and Allocator).
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **Pre-allocation**: Use `make([]T, 0, capacity)` to avoid resize copying.
|
|
14
|
+
2. **Reuse**: Use `sync.Pool` for short-lived buffers.
|
|
15
|
+
3. **Value Semantics**: Pass small structs by value; huge structs by pointer.
|
|
16
|
+
|
|
17
|
+
## Anti-Patterns
|
|
18
|
+
|
|
19
|
+
- **Append Loops**: Appending to a nil slice inside a loop without pre-alloc.
|
|
20
|
+
- **Interface Boxing**: Assigning large values to `interface{}` in hot paths.
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
**Bad:**
|
|
25
|
+
|
|
26
|
+
```go
|
|
27
|
+
var list []int
|
|
28
|
+
for i := 0; i < 1000; i++ {
|
|
29
|
+
list = append(list, i) // Resizes multiple times
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Good:**
|
|
34
|
+
|
|
35
|
+
```go
|
|
36
|
+
list := make([]int, 0, 1000) // One allocation
|
|
37
|
+
for i := 0; i < 1000; i++ {
|
|
38
|
+
list = append(list, i)
|
|
39
|
+
}
|
|
40
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Clean Packages (GO-00006)
|
|
2
|
+
|
|
3
|
+
**Source**: [Standard Go Project Layout](../../../docs/meta/languages/go/08-config-layout.md#1-the-standard-layout)
|
|
4
|
+
**Tags**: #structural #go #architecture #naming
|
|
5
|
+
**Related**: [Deep Modules](../../constitution/CONS-00009-deep-modules.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
Package names must describe _what_ they provide. Project layout must follow the Standard Go Layout.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **Layout**: Use `/cmd` for entry points, `/internal` for private logic, `/pkg` for public libraries.
|
|
14
|
+
2. **Naming**: Reject `utils`, `common`. Use domain-driven names (`auth`, `cryptography`).
|
|
15
|
+
3. **Encapsulation**: Put business logic in `internal/` to prevent accidental external dependency.
|
|
16
|
+
|
|
17
|
+
## Anti-Patterns
|
|
18
|
+
|
|
19
|
+
- **Flat Structure**: Putting everything in root for a complex app.
|
|
20
|
+
- **Bucket Packages**: Dumping unrelated functions into `common`.
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
**Bad:**
|
|
25
|
+
`package utils`
|
|
26
|
+
|
|
27
|
+
**Good:**
|
|
28
|
+
`cmd/server/main.go`
|
|
29
|
+
`internal/auth/service.go`
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Circuit Breakers (GO-00007)
|
|
2
|
+
|
|
3
|
+
**Source**: [btcwallet Engineering Guide](../../../docs/meta/languages/go/03-resilience.md#2-circuit-breakers--rate-limiting)
|
|
4
|
+
**Tags**: #runtime #go #resilience #reliability
|
|
5
|
+
**Related**: [Fallacies](../../constitution/CONS-00019-fallacies.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
Fail fast when dependencies are unhealthy to prevent cascading failures.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **Wrap Calls**: Wrap all external network calls in a Circuit Breaker.
|
|
14
|
+
2. **State Machine**: Implement Closed -> Open -> Half-Open states.
|
|
15
|
+
3. **Fast Failure**: Return "Circuit Open" error immediately without network IO when open.
|
|
16
|
+
|
|
17
|
+
## Anti-Patterns
|
|
18
|
+
|
|
19
|
+
- **Blind Retries**: Retrying a down service 10 times, DDoSing it.
|
|
20
|
+
- **Manual Reset**: Requiring human intervention to close the circuit (should be automatic after timeout).
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
**Bad:**
|
|
25
|
+
|
|
26
|
+
```go
|
|
27
|
+
func Call() error {
|
|
28
|
+
return http.Get(url) // Can hang or fail repeatedly
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Good:**
|
|
33
|
+
|
|
34
|
+
```go
|
|
35
|
+
func Call() error {
|
|
36
|
+
if breaker.IsOpen() {
|
|
37
|
+
return ErrCircuitOpen
|
|
38
|
+
}
|
|
39
|
+
err := http.Get(url)
|
|
40
|
+
breaker.Record(err)
|
|
41
|
+
return err
|
|
42
|
+
}
|
|
43
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Concurrency Safety (GO-00008)
|
|
2
|
+
|
|
3
|
+
**Source**: [btcwallet Engineering Guide](../../../docs/meta/languages/go/06-safety.md#implementation-safety)
|
|
4
|
+
**Tags**: #behavioral #go #concurrency #safety
|
|
5
|
+
**Related**: [Safety](../../constitution/CONS-00015-safety.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
Go's built-in types (Map, Slice) are NOT safe for concurrent access.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **Maps & Slices**: Protect shared maps/slices with a `sync.Mutex` or `sync.RWMutex`.
|
|
14
|
+
2. **Pointers**: Always pass synchronization primitives (`sync.Mutex`, `sync.WaitGroup`) by pointer. Copying them breaks the lock.
|
|
15
|
+
3. **Atomics**: Use `sync/atomic` for simple counters to avoid Mutex overhead.
|
|
16
|
+
|
|
17
|
+
## Anti-Patterns
|
|
18
|
+
|
|
19
|
+
- **Race Conditions**: Reading and writing a map from different goroutines without a lock.
|
|
20
|
+
- **Copied Locks**: `func foo(mu sync.Mutex)` (Pass by value).
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
**Bad:**
|
|
25
|
+
|
|
26
|
+
```go
|
|
27
|
+
// Lock is copied!
|
|
28
|
+
func foo(mu sync.Mutex) {
|
|
29
|
+
mu.Lock()
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Good:**
|
|
34
|
+
|
|
35
|
+
```go
|
|
36
|
+
func foo(mu *sync.Mutex) {
|
|
37
|
+
mu.Lock()
|
|
38
|
+
}
|
|
39
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Table-Driven Tests (GO-00009)
|
|
2
|
+
|
|
3
|
+
**Source**: [Unit Testing Guidelines](../../../docs/meta/languages/go/07-testing.md#2-table-driven-tests)
|
|
4
|
+
**Tags**: #operational #go #testing #tdd
|
|
5
|
+
**Related**: [Test Structure](GO-00015-aaa-pattern.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
Use table-driven tests to exercise the same logic with varying data.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **Data Only**: The test case struct must contain only data (inputs, expected outputs). It must NOT contain functions or setup logic.
|
|
14
|
+
2. **Identical Arrange**: The setup block inside the loop must be identical for every case.
|
|
15
|
+
3. **No Conditionals**: If you need `if tc.flag` to change the mock setup, you must NOT use a table test. Use a standalone test.
|
|
16
|
+
|
|
17
|
+
## Anti-Patterns
|
|
18
|
+
|
|
19
|
+
- **Logic in Structs**: `struct { setup func() }`. This hides the test behavior.
|
|
20
|
+
- **Branching Tests**: A single test loop trying to handle "Success" and "Not Found" where the mock calls differ entirely.
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
**Bad:**
|
|
25
|
+
|
|
26
|
+
```go
|
|
27
|
+
cases := []struct {
|
|
28
|
+
setup func() // Logic hidden here
|
|
29
|
+
}{ ... }
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Good:**
|
|
33
|
+
|
|
34
|
+
```go
|
|
35
|
+
cases := []struct {
|
|
36
|
+
name string
|
|
37
|
+
in int
|
|
38
|
+
want int
|
|
39
|
+
}{ ... }
|
|
40
|
+
|
|
41
|
+
for _, tc := range cases {
|
|
42
|
+
t.Run(tc.name, func(t *testing.T) {
|
|
43
|
+
// Identical Arrange/Act/Assert
|
|
44
|
+
got := Do(tc.in)
|
|
45
|
+
require.Equal(t, tc.want, got)
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Escape Analysis (GO-00010)
|
|
2
|
+
|
|
3
|
+
**Source**: [btcwallet Engineering Guide](../../../docs/meta/languages/go/05-performance.md#2-compiler-optimizations)
|
|
4
|
+
**Tags**: #runtime #go #performance #compiler
|
|
5
|
+
**Related**: [Efficiency](../../constitution/CONS-00025-efficiency.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
Ensure variables are allocated on the stack instead of the heap where possible to reduce GC pressure.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **Check**: Use `go build -gcflags="-m"` to verify escape decisions.
|
|
14
|
+
2. **Pointers**: Avoid returning pointers to small structs; return by value to keep them on the stack.
|
|
15
|
+
|
|
16
|
+
## Anti-Patterns
|
|
17
|
+
|
|
18
|
+
- **Blind Allocation**: Assuming everything is on the stack.
|
|
19
|
+
- **Interface Boxing**: Assigning a small value to an `interface{}` causes it to escape.
|
|
20
|
+
|
|
21
|
+
## Examples
|
|
22
|
+
|
|
23
|
+
**Bad:**
|
|
24
|
+
|
|
25
|
+
```go
|
|
26
|
+
func NewPoint(x, y int) *Point {
|
|
27
|
+
return &Point{x, y} // Escapes to heap
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Good:**
|
|
32
|
+
|
|
33
|
+
```go
|
|
34
|
+
func NewPoint(x, y int) Point {
|
|
35
|
+
return Point{x, y} // Stays on stack
|
|
36
|
+
}
|
|
37
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Retry Strategy (GO-00011)
|
|
2
|
+
|
|
3
|
+
**Source**: [btcwallet Engineering Guide](../../../docs/meta/languages/go/03-resilience.md#3-retry-with-backoff)
|
|
4
|
+
**Tags**: #runtime #go #resilience #reliability
|
|
5
|
+
**Related**: [Fallacies](../../constitution/CONS-00019-fallacies.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
Handle transient failures gracefully with exponential backoff and jitter.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **Transient Only**: Only retry errors that are likely to succeed later (Network, 503). Never retry 400 Bad Request.
|
|
14
|
+
2. **Backoff**: Use exponential backoff (1s, 2s, 4s).
|
|
15
|
+
3. **Jitter**: Add random jitter (+/- 10%) to prevent Thundering Herd.
|
|
16
|
+
|
|
17
|
+
## Anti-Patterns
|
|
18
|
+
|
|
19
|
+
- **Immediate Retry**: `for { try() }` (CPU spin).
|
|
20
|
+
- **Infinite Retry**: Retrying forever without a deadline.
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
**Bad:**
|
|
25
|
+
|
|
26
|
+
```go
|
|
27
|
+
for i := 0; i < 3; i++ {
|
|
28
|
+
if err := connect(); err == nil {
|
|
29
|
+
break
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Good:**
|
|
35
|
+
|
|
36
|
+
```go
|
|
37
|
+
backoff := time.Second
|
|
38
|
+
for i := 0; i < 3; i++ {
|
|
39
|
+
if err := connect(); err == nil {
|
|
40
|
+
break
|
|
41
|
+
}
|
|
42
|
+
time.Sleep(backoff + jitter(backoff))
|
|
43
|
+
backoff *= 2
|
|
44
|
+
}
|
|
45
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Rate Limiting (GO-00012)
|
|
2
|
+
|
|
3
|
+
**Source**: [btcwallet Engineering Guide](../../../docs/meta/languages/go/03-resilience.md#2-circuit-breakers--rate-limiting)
|
|
4
|
+
**Tags**: #runtime #go #resilience #reliability
|
|
5
|
+
**Related**: [Safety](../../constitution/CONS-00015-safety.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
Protect internal resources and downstream services from overload.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **Inbound**: Reject requests if the system is overloaded (Load Shedding).
|
|
14
|
+
2. **Outbound**: Limit the rate of calls to external APIs.
|
|
15
|
+
3. **Library**: Use `golang.org/x/time/rate`.
|
|
16
|
+
|
|
17
|
+
## Anti-Patterns
|
|
18
|
+
|
|
19
|
+
- **Unbounded Work**: Spawning a goroutine for every incoming HTTP request without limit.
|
|
20
|
+
- **Sleep**: Using `time.Sleep` for rate limiting (imprecise).
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
**Bad:**
|
|
25
|
+
|
|
26
|
+
```go
|
|
27
|
+
for req := range requests {
|
|
28
|
+
go process(req) // OOM risk
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Good:**
|
|
33
|
+
|
|
34
|
+
```go
|
|
35
|
+
limiter := rate.NewLimiter(rate.Every(time.Second), 10)
|
|
36
|
+
for req := range requests {
|
|
37
|
+
if err := limiter.Wait(ctx); err != nil {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
go process(req)
|
|
41
|
+
}
|
|
42
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# I/O Buffering (GO-00013)
|
|
2
|
+
|
|
3
|
+
**Source**: [btcwallet Engineering Guide](../../../docs/meta/languages/go/05-performance.md#3-io-optimization)
|
|
4
|
+
**Tags**: #runtime #go #performance #io
|
|
5
|
+
**Related**: [Efficiency](../../constitution/CONS-00025-efficiency.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
Reduce the number of system calls by buffering Input/Output operations.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **Read**: Wrap `io.Reader` in `bufio.NewReader`.
|
|
14
|
+
2. **Write**: Wrap `io.Writer` in `bufio.NewWriter` and ensure `Flush()` is called.
|
|
15
|
+
|
|
16
|
+
## Anti-Patterns
|
|
17
|
+
|
|
18
|
+
- **Syscall Spam**: Calling `Read()` byte-by-byte on a raw file descriptor.
|
|
19
|
+
- **Unbuffered Network**: Writing small packets to a TCP connection one by one.
|
|
20
|
+
|
|
21
|
+
## Examples
|
|
22
|
+
|
|
23
|
+
**Bad:**
|
|
24
|
+
|
|
25
|
+
```go
|
|
26
|
+
f, _ := os.Open("file.txt")
|
|
27
|
+
b := make([]byte, 1)
|
|
28
|
+
for {
|
|
29
|
+
n, _ := f.Read(b) // Syscall per byte
|
|
30
|
+
if n == 0 {
|
|
31
|
+
break
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Good:**
|
|
37
|
+
|
|
38
|
+
```go
|
|
39
|
+
f, _ := os.Open("file.txt")
|
|
40
|
+
r := bufio.NewReader(f)
|
|
41
|
+
b := make([]byte, 1024)
|
|
42
|
+
n, _ := r.Read(b) // Bulk read
|
|
43
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Memory Layout (GO-00014)
|
|
2
|
+
|
|
3
|
+
**Source**: [btcwallet Engineering Guide](../../../docs/meta/languages/go/05-performance.md#2-compiler-optimizations)
|
|
4
|
+
**Tags**: #runtime #go #performance #memory
|
|
5
|
+
**Related**: [Efficiency](../../constitution/CONS-00025-efficiency.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
Minimize memory usage by optimizing struct field order.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **Alignment**: Order struct fields from largest size (int64, pointers) to smallest (bool) to minimize padding bytes.
|
|
14
|
+
2. **Linter**: Use `fieldalignment` to detect inefficiency.
|
|
15
|
+
|
|
16
|
+
## Anti-Patterns
|
|
17
|
+
|
|
18
|
+
- **Padding Waste**: `struct { bool; int64; bool }` wastes 14 bytes (on 64-bit).
|
|
19
|
+
|
|
20
|
+
## Examples
|
|
21
|
+
|
|
22
|
+
**Bad:**
|
|
23
|
+
|
|
24
|
+
```go
|
|
25
|
+
type User struct {
|
|
26
|
+
isAdmin bool // 1 byte + 7 padding
|
|
27
|
+
id int64 // 8 bytes
|
|
28
|
+
active bool // 1 byte + 7 padding
|
|
29
|
+
} // Total: 24 bytes
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Good:**
|
|
33
|
+
|
|
34
|
+
```go
|
|
35
|
+
type User struct {
|
|
36
|
+
id int64 // 8 bytes
|
|
37
|
+
isAdmin bool // 1 byte
|
|
38
|
+
active bool // 1 byte
|
|
39
|
+
// + 6 padding
|
|
40
|
+
} // Total: 16 bytes
|
|
41
|
+
```
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# AAA Pattern (GO-00015)
|
|
2
|
+
|
|
3
|
+
**Source**: [Unit Testing Guidelines](../../../docs/meta/languages/go/07-testing.md#1-aaa-arrange-act-assert)
|
|
4
|
+
**Tags**: #operational #go #testing #readability
|
|
5
|
+
**Related**: [Test Isolation](GO-00018-test-isolation.md)
|
|
6
|
+
|
|
7
|
+
## Definition
|
|
8
|
+
|
|
9
|
+
Tests must follow the Arrange-Act-Assert structure.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
1. **Structure**: Separate the test body into three distinct sections separated by blank lines.
|
|
14
|
+
2. **Order**: Always Arrange first, then Act, then Assert.
|
|
15
|
+
3. **Visuals**: Use blank lines to make the phases obvious.
|
|
16
|
+
|
|
17
|
+
## Anti-Patterns
|
|
18
|
+
|
|
19
|
+
- **Mixed Logic**: Interleaving setup and assertions.
|
|
20
|
+
- **Wall of Code**: No visual separation.
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
**Bad:**
|
|
25
|
+
|
|
26
|
+
```go
|
|
27
|
+
func TestLogic(t *testing.T) {
|
|
28
|
+
x := setup()
|
|
29
|
+
if !x.Run() {
|
|
30
|
+
t.Fail()
|
|
31
|
+
}
|
|
32
|
+
x.cleanup()
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Good:**
|
|
37
|
+
|
|
38
|
+
```go
|
|
39
|
+
func TestLogic_Success(t *testing.T) {
|
|
40
|
+
// Arrange
|
|
41
|
+
s := NewService()
|
|
42
|
+
|
|
43
|
+
// Act
|
|
44
|
+
err := s.Run()
|
|
45
|
+
|
|
46
|
+
// Assert
|
|
47
|
+
require.NoError(t, err)
|
|
48
|
+
}
|
|
49
|
+
```
|