Skip to content

Commit c9c9c03

Browse files
committed
feat: add codeguard workflow with evidence bundle upload
- Configure codeguard-action with custom rubric - Upload evidence bundle as artifact
1 parent 9a2b86d commit c9c9c03

5 files changed

Lines changed: 253 additions & 5 deletions

File tree

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
# Clarity Linter Rubric
2+
# Based on cognitive load theory and code readability research
3+
#
4+
# Cognitive Load Types (Sweller, 1988):
5+
# - Intrinsic: Inherent complexity of the problem
6+
# - Extraneous: Unnecessary complexity from poor presentation
7+
# - Germane: Complexity that aids learning/understanding
8+
#
9+
# Goal: Minimize extraneous cognitive load
10+
11+
name: clarity
12+
version: "1.0"
13+
description: "Clarity analysis measuring cognitive load and readability"
14+
15+
thresholds:
16+
max_cognitive_complexity: 15
17+
max_nesting_depth: 4
18+
max_parameters: 5
19+
max_line_length: 100
20+
max_file_lines: 500
21+
22+
rules:
23+
# Naming Clarity
24+
- id: CLR-001
25+
name: descriptive_names
26+
category: naming
27+
severity: medium
28+
description: "Variable and function names should be self-documenting"
29+
guidance: |
30+
Names should reveal intent:
31+
- Use full words, not abbreviations
32+
- Avoid single-letter names (except i,j,k in loops)
33+
- Name length proportional to scope
34+
- Boolean names should be questions (is_valid, has_items)
35+
patterns:
36+
- "def\\s+[a-z]\\("
37+
- "function\\s+[a-z]\\("
38+
- "(?:const|let|var)\\s+[a-z]\\s*="
39+
40+
- id: CLR-002
41+
name: consistent_naming_convention
42+
category: naming
43+
severity: low
44+
description: "Use consistent naming conventions throughout"
45+
guidance: |
46+
Follow language conventions:
47+
- Python: snake_case for functions/variables, PascalCase for classes
48+
- Constants: UPPER_SNAKE_CASE
49+
- Private: _leading_underscore
50+
patterns:
51+
- "^class\\s+[a-zA-Z]+_[a-zA-Z_]+\\s*[:(]"
52+
- "^(?:export\\s+)?class\\s+[a-zA-Z]+_[a-zA-Z_]+\\s*[{(]"
53+
54+
# Structural Clarity
55+
- id: CLR-003
56+
name: deep_nesting
57+
category: structure
58+
severity: high
59+
description: "Avoid deeply nested code blocks"
60+
guidance: |
61+
Deep nesting increases cognitive load:
62+
- Maximum 4 levels of nesting
63+
- Use early returns (guard clauses)
64+
- Extract nested logic to functions
65+
- Consider State pattern for complex conditions
66+
max_nesting_depth: 4
67+
patterns:
68+
- "^\\s{12,}if\\s*\\("
69+
- "^\\s{12,}for\\s*\\("
70+
- "^\\s{12,}while\\s*\\("
71+
- "^\\s{24,}if"
72+
- "^\\s{24,}for"
73+
- "^\\s{24,}while"
74+
75+
- id: CLR-004
76+
name: long_functions
77+
category: structure
78+
severity: medium
79+
description: "Functions should fit in one mental chunk"
80+
guidance: |
81+
Keep functions short:
82+
- Maximum 30-40 lines ideal
83+
- One level of abstraction
84+
- Single responsibility
85+
- Easy to hold in working memory
86+
max_function_lines: 40
87+
88+
- id: CLR-005
89+
name: parameter_overload
90+
category: structure
91+
severity: high
92+
description: "Too many parameters indicate need for refactoring"
93+
guidance: |
94+
Limit function parameters:
95+
- Maximum 5 parameters
96+
- Use parameter objects for related data
97+
- Consider builder pattern
98+
- Named parameters for clarity
99+
max_parameters: 5
100+
patterns:
101+
- "def\\s+[a-z_]+\\([^)]{400,}\\)"
102+
- "function\\s+\\w+\\([^)]{200,}\\)"
103+
- "\\w+\\s*\\([^)]{200,}\\)\\s*[:{=>]"
104+
105+
# Logical Clarity
106+
- id: CLR-006
107+
name: complex_conditionals
108+
category: logic
109+
severity: high
110+
description: "Complex boolean expressions are hard to reason about"
111+
guidance: |
112+
Simplify conditionals:
113+
- Maximum 3 conditions per expression
114+
- Extract to named boolean variables
115+
- Use De Morgan's laws to simplify
116+
- Consider truth tables for complex logic
117+
patterns:
118+
- "if.*and.*and.*and"
119+
- "if.*or.*or.*or"
120+
- "if.*and.*or.*and"
121+
- "if\\s*\\(.*&&.*&&.*&&"
122+
- "if\\s*\\(.*\\|\\|.*\\|\\|.*\\|\\|"
123+
- "if\\s*\\(.*&&.*\\|\\|.*&&"
124+
125+
- id: CLR-007
126+
name: negation_chains
127+
category: logic
128+
severity: medium
129+
description: "Chains of negations are confusing"
130+
guidance: |
131+
Avoid double/triple negatives:
132+
- not not x -> x
133+
- not is_invalid -> is_valid
134+
- Prefer positive conditions
135+
patterns:
136+
- "^[^#\"']*\\bnot\\s+not\\b"
137+
- "^[^#\"']*!\\s*!"
138+
139+
- id: CLR-008
140+
name: implicit_type_coercion
141+
category: logic
142+
severity: medium
143+
description: "Implicit type coercion obscures intent"
144+
guidance: |
145+
Be explicit about types:
146+
- if x: -> if x is not None:
147+
- if len(x): -> if len(x) > 0:
148+
- Document expected types
149+
patterns:
150+
- "if\\s+not\\s+not\\s+"
151+
152+
# Documentation Clarity
153+
- id: CLR-009
154+
name: missing_docstrings
155+
category: documentation
156+
severity: low
157+
description: "Public functions should have docstrings"
158+
guidance: |
159+
Document public interfaces:
160+
- What the function does
161+
- Parameters and types
162+
- Return value and type
163+
- Exceptions raised
164+
patterns:
165+
- "^def\\s+[a-z][a-z_]{15,}\\([^)]*\\)\\s*:"
166+
- "^(?:export\\s+)?(?:async\\s+)?function\\s+[a-z][a-zA-Z]{15,}\\("
167+
- "^(?:export\\s+)?(?:const|let)\\s+[a-z][a-zA-Z]{15,}\\s*="
168+
169+
- id: CLR-010
170+
name: comment_code_mismatch
171+
category: documentation
172+
severity: high
173+
description: "Comments that contradict code are worse than no comments"
174+
guidance: |
175+
Keep comments synchronized:
176+
- Update comments when code changes
177+
- Prefer self-documenting code
178+
- Comments explain why, not what
179+
- Delete obsolete comments
180+
181+
# Cognitive Load Metrics
182+
- id: CLR-011
183+
name: cyclomatic_complexity
184+
category: metrics
185+
severity: high
186+
description: "High cyclomatic complexity indicates hard-to-test code"
187+
guidance: |
188+
Reduce decision points:
189+
- Maximum complexity of 10-15
190+
- Each if/for/while/except adds 1
191+
- Extract complex branches to functions
192+
max_cyclomatic_complexity: 15
193+
194+
- id: CLR-012
195+
name: cognitive_complexity
196+
category: metrics
197+
severity: high
198+
description: "Cognitive complexity measures code understandability"
199+
guidance: |
200+
Cognitive complexity accounts for:
201+
- Nesting depth (exponential penalty)
202+
- Break in linear flow
203+
- Logical operators
204+
- Recursion
205+
max_cognitive_complexity: 15
206+
207+
- id: CLR-013
208+
name: halstead_difficulty
209+
category: metrics
210+
severity: medium
211+
description: "Halstead difficulty measures programming effort"
212+
guidance: |
213+
Reduce vocabulary and length:
214+
- Fewer unique operators
215+
- Fewer unique operands
216+
- Shorter implementations
217+
max_halstead_difficulty: 30
218+
219+
# Formatting Clarity
220+
- id: CLR-014
221+
name: inconsistent_formatting
222+
category: formatting
223+
severity: low
224+
description: "Inconsistent formatting disrupts reading flow"
225+
guidance: |
226+
Use consistent formatting:
227+
- Configure auto-formatter (black, prettier)
228+
- Consistent indentation
229+
- Consistent spacing around operators
230+
patterns:
231+
- "^[^#]*\\w\\s{4,}=\\s"
232+
- "^[^#]*=\\s{4,}\\w"
233+
234+
- id: CLR-015
235+
name: long_lines
236+
category: formatting
237+
severity: low
238+
description: "Long lines require horizontal scrolling"
239+
guidance: |
240+
Keep lines short:
241+
- Maximum 100 characters
242+
- Break at logical points
243+
- Use line continuation for clarity
244+
max_line_length: 100
245+

.github/scripts/codeguard-local.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ def main():
293293
analysis = analyzer.analyze(diff_content, rubric=args.rubric)
294294

295295
# ---- Classify risk ----
296-
classifier = RiskClassifier(rubric=args.rubric)
296+
classifier = RiskClassifier(rubric=args.rubric, repo_root=repo_root)
297297
risk_result = classifier.classify(analysis)
298298

299299
# ---- Build evidence bundle ----

.github/scripts/test-action-docker.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ def main():
9393
print(f"Lines added: {analysis['lines_added']}")
9494
print(f"Lines removed: {analysis['lines_removed']}")
9595
96-
classifier = RiskClassifier(rubric=rubric)
96+
repo_root = Path(os.environ.get("GITHUB_WORKSPACE", "/workspace"))
97+
classifier = RiskClassifier(rubric=rubric, repo_root=repo_root)
9798
risk_result = classifier.classify(analysis)
9899
risk_tier = risk_result["risk_tier"]
99100
print(f"Risk tier: {risk_tier}")

.github/workflows/codeguard.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ jobs:
1818
- uses: actions/checkout@v4
1919

2020
- name: Run CodeGuard analysis
21-
uses: DNYoussef/codeguard-action@main
21+
id: codeguard
22+
uses: m1el/codeguard-action@main
2223
with:
2324
github_token: ${{ secrets.GITHUB_TOKEN }}
2425
risk_threshold: L3
25-
rubric: default
26+
rubric: .codeguard/rubrics/clarity-mine.yaml
2627
post_comment: "true"
2728
generate_bundle: "true"
2829
fail_on_high_risk: "true"
@@ -34,5 +35,5 @@ jobs:
3435
uses: actions/upload-artifact@v4
3536
with:
3637
name: codeguard-evidence-bundle
37-
path: .guardspine/
38+
path: evidence-bundle/
3839
retention-days: 90

src/transcribe_stream.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#endif
2525

2626
static void print_usage(const char * prog) {
27+
fprintf(stderr, "this is a change that is not that important but it is a change\n");
2728
fprintf(stderr, "Usage: %s <model.gguf> <audio.pcm|-|--stdin> [chunk_ms] [right_context] [--cpu|--cuda]\n", prog);
2829
fprintf(stderr, "\n");
2930
fprintf(stderr, " model.gguf - GGUF model file\n");

0 commit comments

Comments
 (0)