scripts/check-purged-em-dashes.sh enforces zero em dashes on the paths declared in scripts/em-dash-purged-paths.txt. The allowlist is deliberately a positive list, so a path that is not named is unenforced rather than wrongly declared clean, and the gate is designed to grow one shard at a time. It has not grown that way, because the shards that would have added their lines landed before the gate existed.
The gap
The allowlist declares 21 entries expanding to 30 tracked files, covering 10 plugins. Sixty-nine plugins have had a README.md or a skills/*/SKILL.md rewritten by a commit whose subject is de-slop instruction surfaces. The gate therefore defends a small fraction of what the campaign has actually cleaned, and nothing prevents the rest from regressing.
Why the remaining plugins were not simply added
Two thirds of them are not yet clean, and the reason is consistent. Sampling architecture, coupling, tdd, go-format, markdown-format and playwright through the gate: the last three pass, while the first three fail on em dashes in the description: field of a skill's YAML frontmatter rather than in the body prose. That surface was deferred on purpose. PR #3339's own body records the deferral, describing the leftover as belonging to "the later frontmatter and cheat-sheet pass".
So the backfill is not a single mechanical addition. It has three parts:
- Add the plugins that already pass, once each is verified.
- Finish the frontmatter pass for the plugins that fail only on
description:, then add them.
- Decide what to do about
plugins/*/.claude-plugin/plugin.json. Fifty-two of the seventy-one tracked plugin manifests still carry an em dash in their description. No markdown sweep will find them, and the detector the gate drives extracts prose from markdown, so this surface needs either its own check or an explicit decision to leave it unenforced.
What makes the backfill expensive today
Verifying a candidate list means running the gate, and the gate is slow in proportion to the file count. A run over the current 30 files takes roughly nine minutes on a Windows workstation, because the detector forks per file per rule. The gate needs exactly one rule, rule-em-dash, but its throwaway config layer copies the tracked config verbatim and only removes that rule from disabled_rules, so roughly a dozen unrelated rules run on every file and their findings are discarded.
Narrowing the throwaway layer to disable every rule except rule-em-dash would cut the work by about an order of magnitude and make a several-hundred-file allowlist affordable both to verify locally and to run in CI. It was kept out of the gate's introducing change because the gate's liveness assertion reads the detector's own summary lines and compares the handled-file count against the declared count, and changing which rules run needs that arithmetic re-proven through the gate rather than through a direct detector call.
Suggested order
Narrow the rule set first, with the test suite extended to pin the liveness assertion under the narrower config. The backfill then becomes cheap enough to verify in one pass.
Refs #2891
scripts/check-purged-em-dashes.shenforces zero em dashes on the paths declared inscripts/em-dash-purged-paths.txt. The allowlist is deliberately a positive list, so a path that is not named is unenforced rather than wrongly declared clean, and the gate is designed to grow one shard at a time. It has not grown that way, because the shards that would have added their lines landed before the gate existed.The gap
The allowlist declares 21 entries expanding to 30 tracked files, covering 10 plugins. Sixty-nine plugins have had a
README.mdor askills/*/SKILL.mdrewritten by a commit whose subject isde-slop instruction surfaces. The gate therefore defends a small fraction of what the campaign has actually cleaned, and nothing prevents the rest from regressing.Why the remaining plugins were not simply added
Two thirds of them are not yet clean, and the reason is consistent. Sampling
architecture,coupling,tdd,go-format,markdown-formatandplaywrightthrough the gate: the last three pass, while the first three fail on em dashes in thedescription:field of a skill's YAML frontmatter rather than in the body prose. That surface was deferred on purpose. PR #3339's own body records the deferral, describing the leftover as belonging to "the later frontmatter and cheat-sheet pass".So the backfill is not a single mechanical addition. It has three parts:
description:, then add them.plugins/*/.claude-plugin/plugin.json. Fifty-two of the seventy-one tracked plugin manifests still carry an em dash in theirdescription. No markdown sweep will find them, and the detector the gate drives extracts prose from markdown, so this surface needs either its own check or an explicit decision to leave it unenforced.What makes the backfill expensive today
Verifying a candidate list means running the gate, and the gate is slow in proportion to the file count. A run over the current 30 files takes roughly nine minutes on a Windows workstation, because the detector forks per file per rule. The gate needs exactly one rule,
rule-em-dash, but its throwaway config layer copies the tracked config verbatim and only removes that rule fromdisabled_rules, so roughly a dozen unrelated rules run on every file and their findings are discarded.Narrowing the throwaway layer to disable every rule except
rule-em-dashwould cut the work by about an order of magnitude and make a several-hundred-file allowlist affordable both to verify locally and to run in CI. It was kept out of the gate's introducing change because the gate's liveness assertion reads the detector's own summary lines and compares the handled-file count against the declared count, and changing which rules run needs that arithmetic re-proven through the gate rather than through a direct detector call.Suggested order
Narrow the rule set first, with the test suite extended to pin the liveness assertion under the narrower config. The backfill then becomes cheap enough to verify in one pass.
Refs #2891