Skip to content

Narrow the Dale passive-voice rule to sentences that can be made active without inventing an actor - #1772

Merged
jth-nw merged 1 commit into
devfrom
fix/dale-passive-voice-actor
Oct 23, 2026
Merged

jth-nw merged 1 commit into
devfrom
fix/dale-passive-voice-actor

Conversation

@jth-nw

@jth-nw jth-nw commented Oct 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

The Dale passive-voice rule flags every passive sentence and tells the writer to use active voice. That pushes whoever fixes the finding to add an actor the page never named. This PR changes the rule to flag a passive only when it can be rewritten in active voice without changing its meaning.

Why

During a restyle pass on the Threat Manager 3.4 docs, agents cleared passive-voice findings by rewriting old sentences with an invented actor. A scan of the changed lines found 62 of them across 33 pages: 50 turned a past or completed action into "you ..." or "someone ...", and 12 named the product as the actor.

  • "This was pre-created in the Credential Profiles page" became "You pre-created this in the Credential Profiles page". That says the reader created it, and someone else may have.
  • "The Credential Profile name and/or description have been modified" became "You have modified the Credential Profile name and/or description".
  • "as supplied when it was added" became "as you supplied when you added it".

The rule gave no way to leave these alone. Its whole text was "Don't use passive voice. Use active voice instead." The style guide has the same gap: its example names a known actor ("The audit logs are retrieved by the Data Collection Account") and says nothing about a past action by an unknown actor.

The change

  • .claude/skills/dale/rules/passive-voice.yml: new message and reason. The reason states one test: flag a passive only if it can be rewritten in active voice without changing its meaning. The reader counts as the actor when the sentence tells them what to do, so an instruction in the passive is still flagged and becomes a command. If the rewrite would need any other actor the sentence doesn't state, the sentence isn't flagged. The reason carries no examples on purpose, so the model has nothing to copy the shape of.
  • netwrix_style_guide.md: an exception under "Active voice" for past or completed actions with an unknown or irrelevant actor, with a Do and Don't pair for writers.
  • .claude/references/lint-rules.md: regenerated with scripts/quality/gen-lint-digest.mjs because it quotes the rule text. --check reports no drift.

What changes in practice

Sentence Before After
Next, the installer should be run. flagged flagged (becomes "Next, run the installer.")
The audit logs are retrieved by the Data Collection Account. flagged flagged
This profile was pre-created in the Credential Profiles page. flagged not flagged
Roles can be assigned to users. flagged not flagged
The Save button is enabled when any settings are modified. flagged not flagged
Threat Manager sends the email. not flagged not flagged

Testing

I ran scripts/quality/check.mjs on a six-sentence test page (not committed), once with the old rule and twice with the new one. Dale's verdicts are cached by page content and rules, so I changed the control sentence between the two new runs to force a real second run. Both runs gave the same result: the two flagged sentences above, and none of the others. The old rule flagged all five passives.

This is a small synthetic page. Dale is model-based and its verdicts can vary between runs, so I'd value a second opinion on a few real pages.

Notes for reviewers

  • Dale caches verdicts by content and rules, so this change invalidates cached verdicts. Expect fresh model calls on the first run.
  • "Without changing its meaning" is a judgment call. If verdicts turn out unstable, the next step is one short example in the rule, not a longer list.
  • Passive sentences that were flagged before and are not now will no longer be rewritten by the pre-commit loop. That is the intent.

🤖 Generated with Claude Code

…ve without inventing an actor

The rule flagged every passive sentence and told the writer to use active voice. To clear the
finding, a restyle pass rewrote passives that report a past or completed action by an unnamed
actor, adding "you", "someone", or the product as the actor. "This was pre-created in the
Credential Profiles page" became "You pre-created this", which says the reader did it.

The rule now flags a passive only if it can be rewritten in active voice without changing its
meaning. The reader counts as the actor when the sentence tells them what to do, so an
instruction in the passive is still flagged and becomes a command. A passive whose actor is
unstated and that is not an instruction is not flagged.

- passive-voice.yml: new message and reason. The reason states the test and carries no examples,
  so the model has nothing to copy the shape of.
- netwrix_style_guide.md: add an exception under "Active voice" for past or completed actions
  with an unknown or irrelevant actor, with a Do and Don't pair.
- lint-rules.md: regenerated with gen-lint-digest.mjs.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jth-nw
jth-nw deployed to development October 23, 2026 21:51 — with GitHub Actions Active
@github-actions

Copy link
Copy Markdown
Contributor

Code Review

No correctness issues found.

  • passive-voice.yml: The folded >- scalar is valid YAML. Both consumers load it with js-yaml: scripts/quality/lib/dale.mjs (rule loading and prompt) and scripts/quality/gen-lint-digest.mjs. The >- style folds the three lines into one string with no trailing newline, so the prompt text comes out clean. The message value is quoted correctly even though it contains a colon.
  • lint-rules.md: The digest line matches what gen-lint-digest.mjs produces (reason with whitespace collapsed, then the message), so the --check drift test should pass. I checked this by reading the generator; I couldn't run it in this environment.
  • CI: The rule change triggers script-tests.yml, which watches .claude/skills/dale/rules/**. No tests or scripts assert on the old passive-voice wording. The only other mention is the example JSON in vale-autofix.yml, which uses the rule name, and the name hasn't changed.
  • Side effect (expected, noted in the PR): Dale verdict caches are keyed on rule content, so the first runs after merge make fresh model calls.

There are no build, routing, workflow, or security changes.

@jth-nw
jth-nw merged commit 041572f into dev Oct 23, 2026
10 checks passed
@jth-nw
jth-nw deleted the fix/dale-passive-voice-actor branch October 23, 2026 22:11

This branch was successfully deployed

1 active deployment
development — b6e3f537 Deployed Oct 23, 2026 by jth-nw via build-and-deploy #4824
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant