crossplane / crossplane/docs

Proposal: Create a Crossplane-specific Vale configuration

Open
#1,029 0 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
SCSS
Stars
60
Forks
163
Avg merge
15h 20m
Merged PRs (30d)
9

Description

## Summary

The current Vale setup generates **~23,000 lines of output** with **~11,000+ rule violations** across the documentation. The vast majority of these are low-value suggestions that are routinely ignored, undermining the effectiveness of the linter. This proposal recommends a configuration that catches real issues while eliminating noise.

## Current State Analysis

### Problem Summary

| Issue | Impact |
|-------|--------|
| **3,695 E-Prime violations** | `write-good.E-Prime` flags every use of "is", "are", "was" — impractical for any documentation |
| **2,690 duplicate acronym warnings** | `Google.Acronyms` + `Microsoft.Acronyms` both fire for the same acronyms |
| **942 "complex words" suggestions** | Flags "provide" → "give", "determine" → "decide" — often wrong for technical context |
| **582 heading capitalization issues** | Microsoft sentence-case rule conflicts with Crossplane's title-case headings |
| **563 vocabulary suggestions** | "Verify 'allow' with the A-Z word list" — not actionable |
| **7 overlapping style packages** | alex, Google, Microsoft, proselint, write-good, gitlab, Crossplane — creates duplicate/conflicting rules |

### Root Causes

1. **Too many style packages**: Using 7 packages creates massive overlap and conflicting rules
2. **No severity differentiation**: Warnings treated the same as errors, leading to "alert fatigue"
3. **Rules not tuned for technical docs**: E-Prime (avoiding "to be") is for creative writing, not technical documentation
4. **Missing Crossplane-specific acronym exceptions**: CNCF, AWS, GCP, CRD, XRD not in acronym exception lists
5. **Outdated style packages**: Packages are vendored and not updated via `vale sync`
6. **CI fails on ANY output**: Even suggestions block PRs, so authors add `` everywhere

## Proposed Solution

### 1. Simplify Style Package Selection

**Current:** alex, Google, Microsoft, proselint, write-good, gitlab, Crossplane (7 packages)

**Proposed:** Google, Crossplane (2 packages + selective rules from others)

**Rationale:**
- Google Developer Documentation Style Guide is the most appropriate for technical docs
- Consolidating to one primary style eliminates rule conflicts
- Custom Crossplane rules handle project-specific needs
- Cherry-pick individual valuable rules from other packages rather than importing everything

### 2. Implement Tiered Severity Levels

Following [GitLab's best practice](https://docs.gitlab.com/development/documentation/testing/vale/):

| Level | Purpose | CI Behavior | Examples |
|-------|---------|-------------|----------|
| **Error** | Branding, broken content, serious issues | Fails PR | Spelling errors, deprecated terms, broken shortcodes |
| **Warning** | Style guide violations worth fixing | Displays, doesn't fail | Passive voice, sentence length, contractions |
| **Suggestion** | Nice-to-have improvements | Local editor only, ignored in CI | Word choice preferences |

**CI Change:** Only fail on **errors**, display warnings for awareness.

### 3. Disable High-Noise, Low-Value Rules

Rules to **disable entirely**:

| Rule | Reason |
|------|--------|
| `write-good.E-Prime` | Banning "is/are/was" is impractical — generates 3,695 violations |
| `Microsoft.Acronyms` | Duplicate of Google.Acronyms |
| `Microsoft.ComplexWords` | "provide" → "give" is wrong for technical docs |
| `Microsoft.Vocab` | Not actionable ("verify with A-Z word list") |
| `Microsoft.Headings` | Conflicts with Crossplane's title-case heading style |
| `gitlab.ReadingLevel` | Grade-level scoring not meaningful for technical docs |
| `gitlab.FutureTense` | Over-aggressive for docs that describe future behavior |
| `gitlab.Uppercase` | 511 violations, mostly false positives on proper nouns |
| `Google.Parens` | "Use parentheses judiciously" is too vague to be actionable |
| `write-good.Passive` | Duplicate of Google.Passive |
| `proselint.*` | Overlap with Google rules; disable entire package |

### 4. Expand Crossplane Acronym Exceptions

Add to `Google/Acronyms.yml` exceptions or create `Crossplane/Acronyms.yml`:

```yaml
exceptions:
# Cloud providers
- AWS
- GCP
- EKS
- GKE
- AKS
# Kubernetes ecosystem
- CRD
- RBAC
- CNI
- CSI
# Crossplane-specific
- XRD
- XRC
- MRC
- UXP
# Organizations
- CNCF
```

### 5. Modernize Package Management

**Current:** Vendored packages in `utils/vale/styles/` with no version tracking

**Proposed:** Use Vale's native package management:

```ini
# .vale.ini
StylesPath = styles
MinAlertLevel = warning

Packages = Google, alex

[*.md]
BasedOnStyles = Google, Crossplane
```

Then run `vale sync` to download/update packages. This enables:
- Easy updates via `vale sync`
- Version pinning in CI
- Smaller repository size

### 6. Restructure CI Workflow

**Current behavior:** Any Vale output (including suggestions) fails the PR

**Proposed:**

```yaml
- name: Run Vale
run: |
vale --config="./utils/vale/.vale.ini" \
--minAlertLevel=error \
${{ steps.changed-files.outputs.all_changed_files }}
```

This approach:
- Only fails PRs on actual errors
- Still shows warnings/suggestions for author awareness
- Reduces friction while maintaining quality

### 7. Create a Crossplane-Specific Style Package

Consolidate custom rules into a proper `Crossplane` style:

```
utils/vale/styles/Crossplane/
├── Spelling.yml # (existing, enhanced)
├── Acronyms.yml # New: Crossplane/K8s acronyms
├── Terminology.yml # New: Enforce correct product names
├── Headings.yml # New: Crossplane title-case standard
├── vocab/
│ ├── accept.txt # Consolidated word lists
│ └── reject.txt # Terms to avoid
```

**Example `Terminology.yml`:**
```yaml
extends: substitution
message: "Use '%s' instead of '%s'."
level: error
ignorecase: true
swap:
crossplane: Crossplane
kubernetes: Kubernetes
k8s: Kubernetes
helm chart: Helm chart
providerconfig: ProviderConfig
```

## Proposed .vale.ini Configuration

```ini
StylesPath = styles
MinAlertLevel = suggestion

Packages = Google, alex

[*.md]
BasedOnStyles = Google, alex, Crossplane

# === DISABLED RULES ===

# Write-good: Disable impractical rules
write-good.E-Prime = NO
write-good.Passive = NO # Covered by Google.Passive
write-good.TooWordy = NO
write-good.Weasel = NO

# Google: Disable overly pedantic rules
Google.Parens = NO
Google.We = NO # First person acceptable in tutorials

# Microsoft: Don't use (overlaps with Google)
# Not loaded

# GitLab: Don't use (too opinionated for our needs)
# Not loaded

# Proselint: Don't use (overlaps with Google)
# Not loaded

# === RULE LEVEL ADJUSTMENTS ===

# Demote to suggestion (won't fail CI)
Google.Passive = suggestion
Google.Acronyms = suggestion

# Keep as warning (displayed but won't fail CI)
Google.Contractions = warning
alex.Gendered = warning

# Keep as error (will fail CI)
Crossplane.Spelling = error
Crossplane.Terminology = error

# === TOKEN/BLOCK IGNORES ===
TokenIgnores = (\(#.*\)),(\]\(),(http.*),({{<\s*\/?.*>}}),(\!\[),(\d.*px),(\d\.\d\.\d)
BlockIgnores = (\{\{<\s*\/?.*>\}\}),(\{\{\<\/\*.*\*\/\>\}\})
```

## Implementation Plan

### Phase 1: Reduce Noise (Immediate)
1. Disable `write-good.E-Prime` and other high-volume, low-value rules
2. Remove duplicate rules (Microsoft.Acronyms, write-good.Passive)
3. Expand acronym exceptions for Kubernetes/Crossplane terms
4. Update CI to only fail on errors

### Phase 2: Consolidate Packages (Short-term)
1. Remove gitlab, Microsoft, proselint, write-good packages
2. Keep Google as primary style, alex for inclusive language
3. Create `Crossplane/Terminology.yml` for project-specific terms
4. Migrate to `vale sync` package management

### Phase 3: Clean Existing Content (Medium-term)
1. Fix remaining errors in existing docs (now manageable count)
2. Remove scattered `` comments where possible
3. Document which rules are enforced and why

### Phase 4: Continuous Improvement (Ongoing)
1. Review rule violations quarterly
2. Add custom rules for recurring issues
3. Update packages via `vale sync`

## Expected Outcomes

| Metric | Current | After Phase 1 | After Phase 2 |
|--------|---------|---------------|---------------|
| Total violations | ~11,000 | ~1,500 | ~500 |
| Rules that block PRs | All | Errors only | Errors only |
| Actionable violations | ~5% | ~60% | ~90% |
| Style packages | 7 | 7 (with disabled rules) | 3 |

## Appendix: Rule Violation Breakdown

Top violations in current setup:
```
3695 write-good.E-Prime ← DISABLE (impractical)
1345 Microsoft.Acronyms ← DISABLE (duplicate)
1345 Google.Acronyms ← ADD EXCEPTIONS
942 Microsoft.ComplexWords ← DISABLE (wrong for tech docs)
582 Microsoft.Headings ← DISABLE (conflicts with style)
567 Google.Parens ← DISABLE (not actionable)
563 Microsoft.Vocab ← DISABLE (not actionable)
511 gitlab.Uppercase ← DISABLE (false positives)
415 Microsoft.Passive ← DISABLE (duplicate)
415 Google.Passive ← DEMOTE to suggestion
345 gitlab.SentenceLength ← DEMOTE to suggestion
```

Sources:
- [Grafana Writers' Toolkit - Lint prose](https://grafana.com/docs/writers-toolkit/review/lint-prose/)
- [GitLab Vale documentation tests](https://docs.gitlab.com/development/documentation/testing/vale/)
- [Elastic Vale linter docs](https://www.elastic.co/docs/contribute-docs/vale-linter)
- [errata-ai/Google style package](https://github.com/errata-ai/Google)
- [errata-ai/packages repository](https://github.com/errata-ai/packages)

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.