Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 82 additions & 40 deletions .claude/skills/vale-linting/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
- Debugging Vale warnings or errors
- Adding terms to the vocabulary (accept/ignore lists)
- Creating or modifying custom Vale rules
- Understanding why certain patterns are flagged

Check warning on line 20 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.Passive

'are flagged' may be passive voice. Use active voice if you can.

Check notice on line 20 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.E-Prime

Try to avoid using 'are'.

## Quick Reference

Expand All @@ -37,19 +37,24 @@

## Part 1: How Vale Runs

### Docker-Based Execution
### Execution via `.ci/vale/vale.sh`

Vale runs inside a Docker container via `.ci/vale/vale.sh`:
The wrapper script `.ci/vale/vale.sh` runs Vale using:

1. **Local binary** (preferred) — if `vale` is installed and version >= 3.x

Check warning on line 44 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.Passive

'is installed' may be passive voice. Use active voice if you can.

Check notice on line 44 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.E-Prime

Try to avoid using 'is'.
2. **Docker fallback** — `jdkato/vale:v${VALE_VERSION}` (pinned version)

```bash
docker run \
--mount type=bind,src=$(pwd),dst=/workdir \
-w /workdir \
jdkato/vale:latest \
"$@"
# The wrapper handles binary vs Docker automatically
.ci/vale/vale.sh --config=.vale.ini content/path/

# In CI, the pr-vale-check.yml workflow installs the Vale binary
# directly (reads version from vale.sh), so Docker is not needed.
```

**Critical limitation:** Only files inside the repository are accessible. Files in `/tmp` or other external paths will silently fail (Vale falls back to stdin).
**Critical limitation:** Only files inside the repository are accessible when using Docker fallback. Files in `/tmp` or other external paths will silently fail.

Check notice on line 55 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.E-Prime

Try to avoid using 'are'.

**macOS note:** The CI script `.github/scripts/vale-check.sh` uses `declare -A` (associative arrays) which requires bash 4+. macOS ships bash 3.2. Use `/opt/homebrew/bin/bash` or run tests in CI instead.

### Configuration Files

Expand All @@ -64,7 +69,7 @@

### Rule Sources

Vale uses multiple rule sources, configured in `.vale.ini`:

Check warning on line 72 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.TooWordy

'multiple' is too wordy.

```ini
BasedOnStyles = Vale, InfluxDataDocs, Google, write-good
Expand All @@ -77,23 +82,36 @@

### Disabled Rules (and Why)

The following rules are disabled in `.vale.ini` for specific reasons:

```ini
# Vocabulary-based substitution creates false positives in URLs/paths
# Example: /api/v3/write flagged because "api" should be "APIs"
Vale.Terms = NO

# Google.Units flags InfluxDB duration literals (30d, 24h) as needing spaces
# We use custom InfluxDataDocs.Units that only checks byte units
Google.Units = NO

# Flags legitimate technical terms: aggregate, expiration, However, multiple
write-good.TooWordy = NO

# Using custom InfluxDataDocs.Spelling instead
Vale.Spelling = NO
```
Rules are disabled in two categories across `.vale.ini` and all product configs:

Check warning on line 85 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.Passive

'are disabled' may be passive voice. Use active voice if you can.

Check notice on line 85 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.E-Prime

Try to avoid using 'are'.

**Mechanical rules disabled** (replaced by custom equivalents or incompatible with InfluxDB syntax):

| Rule | Reason |
|------|--------|
| `Google.Acronyms` | Custom `InfluxDataDocs.Acronyms` handles this |
| `Google.DateFormat` | Custom `InfluxDataDocs.DateFormat` handles this |
| `Google.Ellipses` | Custom `InfluxDataDocs.Ellipses` handles this |
| `Google.Headings` | Too strict for technical doc headings |
| `Google.WordList` | Custom `InfluxDataDocs.WordList` handles this |
| `Google.Units` | Flags InfluxDB duration literals (30d, 24h); custom `InfluxDataDocs.Units` checks byte units only |
| `Vale.Spelling` | Custom `InfluxDataDocs.Spelling` handles this |
| `Vale.Terms` | False positives from URLs, file paths, and code |

**Style rules disabled** (high false-positive rate in technical docs):

| Rule | Reason |
|------|--------|
| `Google.Contractions` | Not relevant to InfluxData style |
| `Google.FirstPerson` | Tutorials use "I" intentionally |
| `Google.Passive` | Technical docs use passive voice legitimately |
| `Google.We` | "We recommend" is standard in docs |

Check notice on line 107 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.E-Prime

Try to avoid using 'is'.
| `Google.Will` | Future tense is standard in docs |

Check notice on line 108 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.E-Prime

Try to avoid using 'is'.
| `write-good.Cliches` | High false positive rate |
| `write-good.Passive` | Duplicate of Google.Passive concern |
| `write-good.So` | Starting with "So" is fine |

Check notice on line 111 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.E-Prime

Try to avoid using 'is'.
| `write-good.ThereIs` | Often the clearest phrasing |
| `write-good.TooWordy` | Flags legitimate terms: aggregate, expiration, multiple |

Check warning on line 113 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.TooWordy

'multiple' is too wordy.

Check warning on line 113 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.TooWordy

'expiration' is too wordy.

Check warning on line 113 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.TooWordy

'aggregate' is too wordy.
| `write-good.Weasel` | Context-dependent, better handled during content review |

### Active Custom Rules

Expand Down Expand Up @@ -140,14 +158,14 @@

**Key difference in this repo:**

- `accept.txt` - Terms that are part of the shared spelling vocabulary (via `Vocab = InfluxDataDocs`). In this repository, it does **not** currently create substitution rules because `Vale.Terms` is disabled in `.vale.ini`. If `Vale.Terms` is enabled in the future, these terms may also drive substitution behavior.

Check warning on line 161 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.Passive

'is enabled' may be passive voice. Use active voice if you can.

Check warning on line 161 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.Passive

'is disabled' may be passive voice. Use active voice if you can.

Check notice on line 161 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.E-Prime

Try to avoid using 'is'.

Check notice on line 161 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.E-Prime

Try to avoid using 'are'.
- `ignore.txt` - Additional terms to skip in spell checking only (an ignore list layered on top of the shared vocabulary; no substitution rules).

Check warning on line 162 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.TooWordy

'Additional' is too wordy.

### When to Use Each

| Scenario | File |
| --------------------------------------- | ------------ |
| Technical term that's spelled correctly | `ignore.txt` |

Check notice on line 168 in .claude/skills/vale-linting/SKILL.md

View workflow job for this annotation

GitHub Actions / Vale style check

write-good.E-Prime

Try to avoid using 'that's'.
| Preferred capitalization (API, CLI) | `accept.txt` |
| Product name with specific casing | `accept.txt` |
| Variable name appearing in prose | `ignore.txt` |
Expand Down Expand Up @@ -246,7 +264,19 @@
.ci/vale/vale.sh --config=.vale.ini --minAlertLevel=suggestion path/to/file.md
```

## Part 6: TokenIgnores vs Rule Filters
## Part 6: Vale Cannot Inspect URLs

`TokenIgnores` in `.vale.ini` strips all URLs before any rules run:

```ini
TokenIgnores = https?://[^\s\)\]>"]+
```

**This means no Vale rule can match URL content.** An earlier attempt to create a `SupportLink.yml` rule to validate `support.influxdata.com` URL patterns failed for this reason — the URLs were stripped before the rule could see them. Support URL validation uses a separate shell script (`.ci/scripts/check-support-links.sh`) instead.

Keep this in mind when designing rules: if the pattern to match is inside a URL, use a shell script or pre-commit hook, not a Vale rule.

## Part 7: TokenIgnores vs Rule Filters

### TokenIgnores (in .vale.ini)

Expand Down Expand Up @@ -316,27 +346,34 @@
Packages = Google, write-good, Hugo

[*.md]
BasedOnStyles = Vale, InfluxDataDocs, Google, write-good
BasedOnStyles = Vale, InfluxDataDocs, Cloud-Dedicated, Google, write-good

# These rules must be disabled in every product .vale.ini, same as the root .vale.ini.
# --- Disabled mechanical rules ---
Google.Acronyms = NO
Google.DateFormat = NO
Google.Ellipses = NO
Google.Headings = NO
Google.WordList = NO
# Disable Google.Units in favor of InfluxDataDocs.Units which only checks byte
# units (GB, TB, etc). Duration literals (30d, 24h, 1h) are valid InfluxDB syntax.
Google.Units = NO
Vale.Spelling = NO
Vale.Terms = NO

# --- Disabled style rules (high false-positive rate in technical docs) ---
Google.Contractions = NO
Google.FirstPerson = NO
Google.Passive = NO
Google.We = NO
Google.Will = NO
write-good.Cliches = NO
write-good.Passive = NO
write-good.So = NO
write-good.ThereIs = NO
write-good.TooWordy = NO
write-good.Weasel = NO

TokenIgnores = /[a-zA-Z0-9/_\-\.]+, \
https?://[^\s\)\]>"]+, \
`[^`]+`

# Product-specific overrides
InfluxDataDocs.Branding = YES
EOF

# 2. Run Vale with product config
Expand Down Expand Up @@ -373,10 +410,15 @@

## Related Files

| File | Purpose |
| ------------------ | --------------------------------------------- |
| `.vale.ini` | Main configuration |
| `.ci/vale/vale.sh` | Docker wrapper script |
| `.ci/vale/styles/` | All Vale style rules |
| `lefthook.yml` | Pre-commit hooks that run Vale |
| `DOCS-TESTING.md` | Testing documentation (includes Vale section) |
| File | Purpose |
|------|---------|
| `.vale.ini` | Main configuration |
| `.vale-instructions.ini` | Config for non-content files (READMEs, AGENTS.md, etc.) |
| `.ci/vale/vale.sh` | Vale wrapper (local binary or Docker fallback) |
| `.ci/vale/styles/` | All Vale style rules |
| `.ci/scripts/check-support-links.sh` | Support URL validation (can't use Vale — see Part 6) |
| `.github/scripts/vale-check.sh` | CI script: groups files by product config, runs Vale |
| `.github/scripts/resolve-shared-content.sh` | CI script: resolves `content/shared/*` to product pages |
| `.github/workflows/pr-vale-check.yml` | CI workflow: runs Vale on PR changes |
| `lefthook.yml` | Pre-commit hooks that run Vale |
| `DOCS-TESTING.md` | Testing documentation (includes Vale CI section) |
21 changes: 7 additions & 14 deletions .claude/skills/vale-rule-config/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ tokens:
- '(?<=\s)Internet(?! Service Provider| Protocol)'
```

### Critical Limitation: Vale Cannot Match URLs

`TokenIgnores` in `.vale.ini` strips all URLs before rules run. **No rule — `existence`, `substitution`, or `raw` — can match content inside a URL.** This applies globally and cannot be overridden per-rule.

For URL pattern validation (e.g., enforcing canonical support URLs), use a shell script or pre-commit hook instead of a Vale rule. See `.ci/scripts/check-support-links.sh` for an example.

### tokens vs raw

**tokens:**
Expand Down Expand Up @@ -259,20 +265,7 @@ BasedOnStyles = Google, InfluxDataDocs

### Product-Specific Config

Example: `content/influxdb/cloud-dedicated/.vale.ini`

```ini
StylesPath = .ci/vale/styles
MinAlertLevel = error
Vocab = Cloud-Dedicated

[*.md]
BasedOnStyles = Google, InfluxDataDocs, Cloud-Dedicated

# Disable specific rules for this product
Google.Headings = NO
InfluxDataDocs.TechnicalTerms = NO
```
Product configs must mirror all disabled rules from root `.vale.ini` (rules disabled in root are NOT inherited). See the `vale-linting` skill for a complete product config example with all disabled rules.

### Rule Configuration

Expand Down
13 changes: 8 additions & 5 deletions .github/scripts/vale-check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

set -euo pipefail

REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
VALE_WRAPPER="${REPO_ROOT}/.ci/vale/vale.sh"

# Parse arguments
FILES=()
while [[ $# -gt 0 ]]; do
Expand Down Expand Up @@ -51,6 +54,8 @@ get_vale_config() {
case "$file" in
content/influxdb3/cloud-dedicated/*) echo "content/influxdb3/cloud-dedicated/.vale.ini" ;;
content/influxdb3/cloud-serverless/*) echo "content/influxdb3/cloud-serverless/.vale.ini" ;;
content/influxdb3/clustered/*) echo "content/influxdb3/clustered/.vale.ini" ;;
content/influxdb3/core/*) echo "content/influxdb3/core/.vale.ini" ;;
content/influxdb/v2/*) echo "content/influxdb/v2/.vale.ini" ;;
content/*) echo ".vale.ini" ;;
*) echo ".vale-instructions.ini" ;;
Expand All @@ -75,11 +80,9 @@ for config in "${!CONFIG_GROUPS[@]}"; do

echo "Running Vale with config: $config (${#file_array[@]} files)" >&2

# Run Vale via Docker
RESULT=$(docker run --rm \
-v "$(pwd)":/workdir \
-w /workdir \
jdkato/vale:latest \
# Run Vale via the repo wrapper (.ci/vale/vale.sh),
# which uses a local binary if available or falls back to Docker.
RESULT=$("$VALE_WRAPPER" \
--config="$config" \
--output=JSON \
--minAlertLevel=suggestion \
Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/pr-vale-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,19 @@ jobs:
RESOLVED_COUNT=$(wc -l < resolved_files.txt | tr -d ' ')
echo "resolved-count=$RESOLVED_COUNT" >> $GITHUB_OUTPUT

- name: Install Vale
if: steps.detect.outputs.has-files == 'true'
run: |
VALE_VERSION=$(sed -n 's/^VALE_VERSION="\(.*\)"/\1/p' .ci/vale/vale.sh)
curl -sfL "https://github.com/errata-ai/vale/releases/download/v${VALE_VERSION}/vale_${VALE_VERSION}_Linux_64-bit.tar.gz" \
| sudo tar xz -C /usr/local/bin vale
vale --version

- name: Run Vale
if: steps.detect.outputs.has-files == 'true'
id: vale
run: |
chmod +x .github/scripts/vale-check.sh
chmod +x .github/scripts/vale-check.sh .ci/vale/vale.sh

set +e # Don't exit on error
.github/scripts/vale-check.sh --files resolved_files.txt > vale_results.json 2>vale_stderr.txt
Expand Down
19 changes: 15 additions & 4 deletions .vale.ini
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ TokenIgnores = /[a-zA-Z0-9/_\-\.]+, \
https?://[^\s\)\]>"]+, \
`[^`]+`

# --- Disabled mechanical rules ---
Google.Acronyms = NO
Google.DateFormat = NO
Google.Ellipses = NO
Expand All @@ -29,7 +30,17 @@ Vale.Spelling = NO
# false positives from URLs, file paths, and code. The accepted terms in
# accept.txt still work for spelling checks via InfluxDataDocs.Spelling.
Vale.Terms = NO
# Disable write-good.TooWordy - flags legitimate technical terms like
# "aggregate", "expiration", "multiple", "However" that are standard in
# database documentation.
write-good.TooWordy = NO

# --- Disabled style rules (high false-positive rate in technical docs) ---
Google.Contractions = NO
Google.FirstPerson = NO
Google.Passive = NO
Google.We = NO
Google.Will = NO
write-good.Cliches = NO
write-good.Passive = NO
write-good.So = NO
write-good.ThereIs = NO
# Flags legitimate technical terms like "aggregate", "expiration", "multiple".
write-good.TooWordy = NO
write-good.Weasel = NO
2 changes: 1 addition & 1 deletion DOCS-TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ Vale runs automatically on pull requests that modify markdown files. The workflo
1. Detects changed markdown files (content, README, instruction files)
2. Resolves shared content to consuming product pages
3. Maps files to appropriate Vale configs (matching local Lefthook behavior)
4. Runs Vale via Docker (`jdkato/vale:latest`)
4. Runs Vale via `.ci/vale/vale.sh` (local binary or Docker fallback)
5. Reports results as inline annotations and a PR summary comment

**Alert levels:**
Expand Down
17 changes: 14 additions & 3 deletions content/influxdb/v2/.vale.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Packages = Google, write-good, Hugo
[*.md]
BasedOnStyles = Vale, InfluxDBv2, InfluxDataDocs, Google, write-good

# --- Disabled mechanical rules ---
Google.Acronyms = NO
Google.DateFormat = NO
Google.Ellipses = NO
Expand All @@ -22,10 +23,20 @@ Vale.Spelling = NO
# false positives from URLs, file paths, and code. The accepted terms in
# accept.txt still work for spelling checks via InfluxDataDocs.Spelling.
Vale.Terms = NO
# Disable write-good.TooWordy - flags legitimate technical terms like
# "aggregate", "expiration", "multiple", "However" that are standard in
# database documentation.

# --- Disabled style rules (high false-positive rate in technical docs) ---
Google.Contractions = NO
Google.FirstPerson = NO
Google.Passive = NO
Google.We = NO
Google.Will = NO
write-good.Cliches = NO
write-good.Passive = NO
write-good.So = NO
write-good.ThereIs = NO
# Flags legitimate technical terms like "aggregate", "expiration", "multiple".
write-good.TooWordy = NO
write-good.Weasel = NO

# Ignore URL paths like /api/v3/..., /cli/..., /influxdb3/...
# Ignore full URLs like https://example.com/...
Expand Down
17 changes: 14 additions & 3 deletions content/influxdb3/cloud-dedicated/.vale.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Packages = Google, write-good, Hugo
[*.md]
BasedOnStyles = Vale, InfluxDataDocs, Cloud-Dedicated, Google, write-good

# --- Disabled mechanical rules ---
Google.Acronyms = NO
Google.DateFormat = NO
Google.Ellipses = NO
Expand All @@ -22,10 +23,20 @@ Vale.Spelling = NO
# false positives from URLs, file paths, and code. The accepted terms in
# accept.txt still work for spelling checks via InfluxDataDocs.Spelling.
Vale.Terms = NO
# Disable write-good.TooWordy - flags legitimate technical terms like
# "aggregate", "expiration", "multiple", "However" that are standard in
# database documentation.

# --- Disabled style rules (high false-positive rate in technical docs) ---
Google.Contractions = NO
Google.FirstPerson = NO
Google.Passive = NO
Google.We = NO
Google.Will = NO
write-good.Cliches = NO
write-good.Passive = NO
write-good.So = NO
write-good.ThereIs = NO
# Flags legitimate technical terms like "aggregate", "expiration", "multiple".
write-good.TooWordy = NO
write-good.Weasel = NO

# Ignore URL paths like /api/v3/..., /cli/..., /influxdb3/...
# Ignore full URLs like https://example.com/...
Expand Down
17 changes: 14 additions & 3 deletions content/influxdb3/cloud-serverless/.vale.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Packages = Google, write-good, Hugo
[*.md]
BasedOnStyles = Vale, InfluxDataDocs, Cloud-Serverless, Google, write-good

# --- Disabled mechanical rules ---
Google.Acronyms = NO
Google.DateFormat = NO
Google.Ellipses = NO
Expand All @@ -22,10 +23,20 @@ Vale.Spelling = NO
# false positives from URLs, file paths, and code. The accepted terms in
# accept.txt still work for spelling checks via InfluxDataDocs.Spelling.
Vale.Terms = NO
# Disable write-good.TooWordy - flags legitimate technical terms like
# "aggregate", "expiration", "multiple", "However" that are standard in
# database documentation.

# --- Disabled style rules (high false-positive rate in technical docs) ---
Google.Contractions = NO
Google.FirstPerson = NO
Google.Passive = NO
Google.We = NO
Google.Will = NO
write-good.Cliches = NO
write-good.Passive = NO
write-good.So = NO
write-good.ThereIs = NO
# Flags legitimate technical terms like "aggregate", "expiration", "multiple".
write-good.TooWordy = NO
write-good.Weasel = NO

# Ignore URL paths like /api/v3/..., /cli/..., /influxdb3/...
# Ignore full URLs like https://example.com/...
Expand Down
Loading
Loading