feat(ai-slop): unslop-inspired catalog additions, plus the corrections and dogfood config that make them true (0.2.0) - #3031
Conversation
Adapt the unslop skill from cursor/plugins pstack (MIT, pinned at 99559f2) into the ai-slop audit skill, deduplicated against the Wikipedia-derived inventory in a catalog overlap map. - Catalog: second attribution and drift record, 7 new entries (3 script, 4 rubric), inline-header-lists boundary refinement, second calibration pass recorded. - Detector: rule-chatbot-artifacts, rule-filler-phrases, rule-stacked-hedging pattern rules; plain-word trio joins the vocabulary default. Tests extended to 65 cases. - Crosswalk: three argued rows (chatbot-artifacts IMPORTANT, the other two SUGGESTION); adopter tier-spread counts updated; convention CHANGELOG 2.3.0; emitter tier/action mirror updated. - New reference/rewrite-guide.md owns fix-time guidance (plain speech, substitution guardrails, voice, self-audit); fix flow reads it first. - Version 0.2.0; README, CHANGELOG, plugin.json, docs listings synced. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AqwX2njhiLMWGrMg3QNt4g
Follow-up folded into the same unreviewed branch rather than shipping 0.2.0 with a changelog advertising an inert feature. Version stays 0.2.0. Attribution: the Cursor upstream is now a single "inspired by" link. The licence apparatus and the commit-pinned second drift record are removed; the Wikipedia CC BY-SA block is untouched, being a different licence with its own share-alike terms. Honesty defects — four places a doc claimed coverage the code does not provide: - Overlap map header says "catalogued by", not "covered by", and names the rows whose entries are recorded-only and therefore dormant. - Name-dropping recorded as deliberately out of scope for general prose; it had been mapped to a rule describing the opposite tell. - Generic conclusions recorded as detected only in the formulaic half; the named rubric fallback cannot reach a bare optimism closer. - inline-header-lists refinement labelled calibration pre-work, not a live boundary. Drift guards: - All 15 rules' emitted tiers asserted (was 2), plus a roster-set check so a rule added without a crosswalk row cannot emit SUGGESTION by silent fall-through. - tier: frontmatter and --tier retired from emit-findings.sh; both owner docs already said this producer omits it. - Test config isolation: fixtures pin HOME and CLAUDE_PROJECT_DIR to empty dirs. Found by dogfooding, when this repo's own house-style exemption turned nine unrelated cases red. Dogfooding: .claude/ai-slop.json disables rule-em-dash with a recorded reason. First repo-wide run drops ~34,900 findings to 173 across 1212 files, making the audit usable here for the first time. Also: ai-slop registered in the config-cascade Implementers table (the surface implemented the cascade from its first release and was never tabled); relay expectations narrowed to rule-utm-params; word-list narrowings that were silent are now recorded. Suite: 84 cases pass, up from 65. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AqwX2njhiLMWGrMg3QNt4g
|
Claude finished @kyle-sexton's task in 1m 30s —— View job Security review (
|
docs/topics/<slug>/ is contract tier per the topic-docs convention: committed on a task branch, pruned before merge once its durable outcomes have graduated. Both deferred questions are now tracker items: - #3032 — whether any shipped rule appears under Wikipedia's "Ineffective indicators", which is a guardrail question on rule-em-dash and rule-rule-of-three. Blocked here by the research environment's Wikimedia egress denial, not by scope. - #3033 — letting a detector-findings producer name the remediation skill its findings need. The real fix for the relay gap this PR only narrowed the claim about. The Brief's constraints and acceptance criteria are carried by the PR body; the interview ledger stays in the gitignored memory slice. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AqwX2njhiLMWGrMg3QNt4g
|
Last security-reviewed head: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8e7731a233
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The changelog-parity gate requires `## [<version>]`; both entries were written unbracketed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AqwX2njhiLMWGrMg3QNt4g
…-integration-l8gr0k
|
Claude finished @kyle-sexton's task in 5m 34s —— View job Claude code review (
|
|
Claude finished @kyle-sexton's task in 1m 0s —— View job Security review (
|
|
Claude has reviewed this PR 2 times. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
Reported in review and reproduced before fixing: "These are great questions for the reviewer" fired rule-chatbot-artifacts, which emits at IMPORTANT tier, because the listed phrase merely prefixed a longer word. Same class hit "found the smoking guns". The registry gains a per-rule whole-word flag using POSIX -w rather than GNU \b, since this script's cross-grep parity claim rests on POSIX ERE only. It is ON for the five phrase-list rules and OFF where a match legitimately abuts a word character: the byte-class rules (em dash, emoji, curly quotes), the two EREs carrying wildcards, the citation tokens (`[cite:` is followed by digits), and `utm_[a-z]+=` (followed by its value). Both reported cases and their true-positive counterparts are now fixtures, so a rule silenced into uselessness fails as loudly as one that over-fires. Suite: 86 cases pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AqwX2njhiLMWGrMg3QNt4g
|
Claude finished @kyle-sexton's task in 50s —— View job Security review (
|
|
Claude finished @kyle-sexton's task in 5m 23s —— View job Code review (
|
| noise). | ||
| - `rule-abstract-metaphor-jargon` stays rubric, not script, on measurement: "substrate" alone hit | ||
| 114 times in legitimate technical use on this corpus. A word-list scan cannot make the |
There was a problem hiding this comment.
Measurement mismatch: this file says 114, the PR description says 103.
rule-abstract-metaphor-jargonstays rubric, not script, on measurement: "substrate" alone hit 114 times in legitimate technical use on this corpus.
The PR body's Summary states: "rule-abstract-metaphor-jargon was deliberately kept out of the script layer on measurement: 'substrate' alone had 103 legitimate technical uses in this corpus."
plugins/ai-slop/CHANGELOG.md's new [0.2.0] entry agrees with this file (114), so the two shipped artifacts are internally consistent with each other — only the PR description disagrees, and it has said 103 since the PR was opened (unchanged across all three commits and two prior review passes). A rough independent count (git ls-files '*.md' | xargs grep -ilw substrate, whole-word case-insensitive, tracked markdown) turns up 34 files, so neither number is obviously implausible without knowing the exact corpus scope/date the calibration pass used — but given this PR's entire second commit exists to make the plugin's claims about itself match reality, a number that disagrees with itself across the PR body vs. the shipped doc is worth reconciling (or explaining the source of the discrepancy) before merge.
…reach (0.2.1) (#3039) No linked issue ## Summary `ai-slop` ships two detection layers. The deterministic one has 86 shell cases covering all 15 script rules, tiers, roster agreement, exemptions, and portability. The judgment one — 11 rubric tells, plus the `rewrite-guide.md` the fix flow reads at step 1 — had **zero** coverage. That is the half only a model performs, so it is the half evals exist for. This adds 7 eval cases (audit 4 → 9, setup 3 → 5), bringing `ai-slop` in line with sibling audit skills (7, 9, and 14). ## Fix **`audit`, five new cases**, each tied to a documented behavior that no shell test can assert: - **`rubric-findings-reach-the-report-not-the-findings-file`** — the V1 relay boundary. A rubric verdict has no crosswalk row to look a tier up from, so it reaches the human report only. Silently dropping it from the file and silently including it are both failures, and only a model can tell them apart. - **`fix-never-swaps-one-tell-for-another`** — the substitution guardrail. An em dash must resolve to a comma, a period, or a restructured sentence, never a parenthesis or en dash. This is the guardrail most likely to be violated silently, because the swap *looks* like a fix. - **`triads-collapse-toward-the-strongest-item`** — a `rule-of-three` fix collapses toward one item rather than being repunctuated into a three-item list, and keeps a triad whose elements are each load-bearing, saying why. - **`known-false-positive-routes-to-config-not-a-rewrite`** — prose *about* model knowledge cutoffs trips `rule-knowledge-cutoff-disclaimer`. The catalog's calibration record already names this class; the recorded answer is a marker or config exclusion with a stated reason, never weakening the shipped rule to make one corpus pass. - **`declined-exemptions-are-named-with-their-cause`** — a disabled rule and an excluded path must read as decisions, not as an absence of findings. **`setup`, two new cases** covering the `_comment` rationale key introduced in 0.2.0: it is a documented annotation rather than unknown-key drift (while genuinely unknown keys still flag), and disabling a rule records *why* alongside the trade-off against `em_dash_allowed_paths`. **Every case now carries `narration: true`.** The four original cases named `docs/example.md`, which resolves nowhere — a live skill-quality Q4 warning that the flag exists to answer. ## Verification - `check-jsonschema` against `plugins/skill-quality/reference/evals.schema.json` — both files `ok`. - `scripts/check-changelog-parity.sh --check` and `--check-bump origin/main` — both pass at 0.2.1. - `plugins/ai-slop/skills/audit/scripts/detect.test.sh` — 86 cases pass, unchanged (this PR adds no rules). - `node scripts/generate-catalog.mjs` — catalog already in sync. - `markdownlint-cli2` and `typos` clean on the touched files. **Dogfood context that motivated the selection.** A repo-wide run on `main` now reports 174 findings across 1214 files, and sampling them shows the plugin predicting its own false-positive profile: 16 of 21 `rule-emoji-formatting` findings are ❌/✅ semantic wrong-right markers (a documentation convention here, not decoration), 8 `rule-knowledge-cutoff-disclaimer` findings are the class the calibration record already names, and 72 `rule-curly-artifacts` findings concentrate in just 7 files as genuine paste residue. Two of the new evals encode exactly the judgment those findings require. ## Related - Refs #3031 — the 0.2.0 integration this covers the judgment half of. - The de-slop pass over those 174 findings is deliberately NOT in this PR: a large share are the repo's own conventions, so the next step there is config tuning rather than editing prose, and it touches ~100 unrelated documents. --- _Generated by [Claude Code](https://claude.ai/code/session_01AqwX2njhiLMWGrMg3QNt4g)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
… skill (0.26.0) (#3068) Closes #3033 ## Summary The `detector-findings` convention lets a producer emit a findings file that `review:fanout`'s `fix` action consumes. The relay then decided **how** to remediate — and for `ai-slop:audit` that decision was wrong for 14 of its 15 rules. Those rows are prose-style findings. They classify as **cleanup** by content, and `fix-pass-mode.md` Step 4 hands the whole cleanup class to `/simplify` — a **code**-simplification skill that, in its own words, "rediscovers cleanups from the working-tree diff — it does NOT read the findings files", and which never loads `plugins/ai-slop/skills/audit/reference/rewrite-guide.md` where that plugin's rewrite discipline lives. Step 5 then retired the file anyway. A relay pass over an `ai-slop:audit` findings file reported a clean run while applying at most `rule-utm-params`, the one genuinely auto-applicable rule. #3031 narrowed the plugin's own claim to say exactly that, which was honest and left the gap. This teaches the contract to let a producer name the skill that owns its findings' remediation, and teaches the relay to honor it — **without a new field, and without any producer changing what it emits.** ### The question settled first: does an existing disposition already cover this? Asked before anything was written, because a third disposition an existing one already covers is pure cost. **It does not**, on two independent grounds: 1. **Off-site is a statement about the SITE, and these repairs are at `Location`.** `docs/conventions/detector-findings/README.md` "When the remediation is not at `Location`" binds its producer obligation to "a rule whose remediation can lie **outside `Location`'s file**", and both limbs of the consumer's trigger in `fix-pass-mode.md` "Step 2" are site limbs — the `Action` names a different file, or the contract declares the rule off-site. `testing:audit`'s own adopter row states the contrast: its `Location` "IS the remediation site". Claiming off-site to reach the disposition would assert something false about where the fix goes, the same defect the doc already forbids in retargeting `Location`. And it routes to **surface-only**, which trades a wrong apply for no apply rather than closing the gap. 2. **`Auto-applicable: No` has no path to the route that actually misapplies these rows.** Step 4's surface-instead-of-auto-applying fence sits under its **correctness-class** heading. Cleanup-class rows go to `/simplify` wholesale, consulting no crosswalk cell. The column can already say a rule is not auto-applicable and still not stop the apply. The fresh-context verifier confirmed this independently: before this change, `grep -n "Auto-applicable" fix-pass-mode.md` returned **zero hits** — the relay read that column nowhere. Evidence went toward a new **disposition**, not a new **field**. No column was added to the crosswalk and nothing changed in the findings-file shape (`default-mode.md` "Findings-file shape"). ## Fix **Producer side** — `docs/conventions/detector-findings/README.md` 2.4.0, new section "When the remediation is owned by the producer's own skill". A rule whose repair is contained to `Location` but safe only under discipline the producer owns **leads its crosswalk `Auto-applicable` cell with** ``No, remediated by `<invocation>` `` — the invocation written as a code span, whose delimiters a consumer strips before matching. The declaration is **per rule and lives only in the crosswalk** — this contract's own settle-once rule applied rather than restated. "Auto-applicability is settled per rule, at contract time" already says a rule's remediation shape does not vary run to run, and who owns the repair is exactly such a fact. Requiring every emitted row to carry a copy would be the per-finding restatement that section forbids, and would make conformance a property of a producer's *emitter* rather than of its rule set. **Consumer side** — `review` 0.26.0, `fix-pass-mode.md`: - **Step 2** gains one classification rule. It resolves the declaration through the qualified rule id every conforming row already leads its `Finding` cell with, against the crosswalk registry that id "resolves against by exact match" — the contract's own pre-existing words. **The crosswalk declaration is NECESSARY**: an `Action` cell leading with ``Remediate with `<invocation>` `` corroborates it and can never substitute for it, and a rule with no crosswalk declaration takes its ordinary class however its `Action` reads. Off-site is decided first, and an unresolvable contract is the no-declaration case — never a licence to fall back to the `Action` cell. - **Step 4** gains the route, with **no direct-apply fallback** — the asymmetry with `/simplify` is the point. Only an invocation already available in the session is invoked; nothing is installed, fetched, or loosely name-matched, because Step 1 already establishes that nothing authenticates the writer of a findings file. An unavailable or unrecognized invocation **surfaces** its rows, naming what the producer asked for. - **Steps 3 and 5** count and report the route, and the counts **partition** rather than overlap: a row routed to a producer-owned surface is counted there and never on the cleanup line, mirroring the existing correctness/surface-only rule in both the plan block and the report block. - Three evals added: `fix-pass-producer-owned-routes-to-named-surface`, `fix-pass-producer-owned-surface-unavailable`, and `fix-pass-action-cell-alone-never-routes`. **Producer adoption** — `ai-slop` 0.3.1. The 14 non-`rule-utm-params` rows now carry the declaration and `rule-utm-params` stays auto-applicable, with **zero change to what the producer emits** — `ai-slop:audit` already leads every emitted `Finding` cell with its qualified rule id, which is why siting the declaration in the crosswalk closes the gap on its own. `plugins/ai-slop/skills/audit/SKILL.md` is corrected to match: it previously said the relay "retires the findings without fixing them" and to recommend `review:fanout fix` only for `rule-utm-params`, which this change makes false. It now draws the distinction where it actually falls — **what the relay APPLIES is narrow; what it ROUTES is not** — and states the one condition that changes the answer, that the relay can only hand rows over when `/ai-slop:audit` is available in that session, and surfaces them otherwise. **Neither other adopter changes, and neither was touched.** `mutation-testing:audit` declares no owner and is off-site, which Step 2 decides first. `testing:audit` declares no owner because no skill owns choosing the assertion a behavior deserves; its rows keep the plain `No — <reason>` form and are surfaced by Step 4's judgment fence exactly as before. All three adopter rows now state their disposition explicitly. ## Verification | Gate | Result | |---|---| | `check-detector-findings-crosswalk.sh --check` + its self-test | PASS — 22 rule rows, every disposition argued | | `check-changelog-parity.sh` `--check` / `--check-bump origin/main` / `--check-order` / `--check-preserved origin/main` | PASS (83 changelogs newest-first; 64 headings compared) | | `check-changed-skills.sh origin/main` | `audit: PASS — 0 errors`, `fanout: PASS — 0 errors` | | `check-stale-base-overlap.sh --check origin/main` | up to date with `origin/main` | | `check-contract-clause-coverage.py` | PASS | | `check-contract-slice-prune.sh --check` / `--check-diff origin/main` | PASS | | `check-cross-plugin-source-drift.sh --check` | PASS | | `check-evals-quality.sh` on both changed eval sets | PASS — 0 warnings | | `markdownlint-cli2` on every changed markdown file | PASS — 0 issues | | `detect.test.sh` (regression check) | all 92 cases passed | | `node scripts/generate-catalog.mjs` | Catalog already in sync; `docs/CATALOG.md` unchanged | ### Fresh-context verification Separate opus verifiers, in fresh context and told to judge the final state rather than any description of it, reviewed this. The first found **three** real defects, all fixed: the `mutation-testing:audit` adopter row misdescribed two of its own `Auto-applicable` cells; the declared lead was written as a code span in the shipped cells but bare in the contract, so a consumer implementing it literally would match nothing; and the contract-reachability argument was evidence about the **producer's** session rather than the consumer's. Its full verdict is on [#3033](#3033 (comment)). ### Review findings, all fixed - **P1 — routing on an `Action` cell alone.** The original text let the untrusted half of the pair authorize a route by itself. Since nothing authenticates a findings file's writer, any component able to write one could have named any already-installed skill and handed it arbitrary rows, with effects bounded neither by `Location` nor by Step 2. Now the crosswalk declaration is necessary and the `Action` cell only corroborates — the trust boundary being that the crosswalk lives in the consuming repo's own docs, **outside** the artifact being consumed, while the `Action` cell is inside it. **Availability is not authentication.** - **P2 — ambiguous plan counts.** The cleanup and producer-owned lines now partition rows explicitly, in both the plan and the report, so a plan can no longer print `Cleanup-class (14) → /simplify` for rows that never reach `/simplify`. - **P2 — the producer steering operators off the new route.** `ai-slop`'s `SKILL.md`, corrected above. ## Related - #3031 narrowed `ai-slop`'s relay claim to what was then true, and left this gap open on purpose. - #3041 / #3063 backed the `ai-slop` audit evals with committed fixtures; `ai-slop` 0.3.1 here builds on the 0.3.0 that shipped there. - `docs/conventions/detector-findings/README.md` — "The severity crosswalk", the `Auto-applicable` column, "When the remediation is not at `Location`" (the precedent this is argued against, whose rejected remediation-target column is why no column was added here), and the Adopters table. - `plugins/review/skills/fanout/context/fix-pass-mode.md` — the consumer algorithm this teaches to honor the declaration. ### Follow-up, deliberately not in this PR Two `ai-slop` items are tracked separately and nothing here depends on either. `emit-findings.sh` writes `date: …T05-45-10Z` — hyphens where ISO-8601 needs colons in the time portion; Step 1 classes that UNREADABLE and fails **open**, so it costs at most one extra pass and drops nothing. And `docs/upstream/cursor-pstack.md` carries no `unslop` row, although it calls itself the single source of truth for everything derived from that upstream collection and its recheck trigger only covers rows its table names. Merge ordering, disclosed rather than closed: the relay's only contract URL points at `main`, so the new crosswalk cells are not visible to a live relay until this merges. --------- Co-authored-by: Claude <noreply@anthropic.com>
…ion table `docs/upstream/cursor-pstack.md` claims to be the single source of truth for everything in this marketplace derived from cursor/plugins' `pstack/skills/` collection, and its recheck trigger fires only on a change to a `pstack/skills/<name>/SKILL.md` **named in the attribution table**. `unslop` is a member of that collection and `ai-slop` 0.2.0 (#3031) is derived from it, but the table carried no `unslop` row — so the SSOT claim was false and drift in `pstack/skills/unslop/SKILL.md` would have gone undetected. One row, grounded in what is actually in the repo: the seven catalog entries the Wikipedia inventory did not already carry, the plain-word trio in the shipped vocabulary default, and `reference/rewrite-guide.md` as the home for the upstream file's fix-time half; against the overlap map's deduplication, the Name-dropping and Generic-conclusions exclusions, the calibration measurement that kept abstract metaphor nouns out of the script layer, and the one adding-soul bullet that did not survive. The row says on its face that it was NOT audited at this file's `main@60c641e4` pin: the verdict was formed at integration time against an unpinned upstream `main`, and the catalog's own four-part drift record covers the Wikipedia source page only. The pin is the row's baseline for the next diff, not a claim about the state it was audited at. Not one of the port's ten lanes and it does not claim to be — `ai-slop` 0.2.0 landed before this file existed, so "All ten lanes are decided" is unchanged. Docs-only, outside `plugins/`: no version bump and no plugin CHANGELOG entry. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AqwX2njhiLMWGrMg3QNt4g
…#3076) Closes #3032 ## Summary `ai-slop`'s catalog cited Wikipedia's Signs of AI writing but recorded **Ineffective indicators** (and **Comment-specific indicators**) as a fetch gap. That left a guardrail question open: if a shipped rule appeared in the section the page's own editors call unreliable, we would be shipping a tell our source rejects. A 2026-08-21 retrieval answers it: **none of the 15 shipped script rules appear there**, so no rule is dropped or re-scoped. ## Fix - Closed the fetch gap in `plugins/ai-slop/skills/audit/reference/catalog.md` against two revisions of <https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing>: - Catalog pin [1369699198](https://en.wikipedia.org/w/index.php?title=Wikipedia:Signs_of_AI_writing&oldid=1369699198) (2026-08-16), MediaWiki parse sections 80 / 62 / 29. - Live page revision [1370403579](https://en.wikipedia.org/w/index.php?title=Wikipedia:Signs_of_AI_writing&oldid=1370403579) (`2026-08-20T23:13:41Z`), retrieved 2026-08-21. - Quoted the eight ineffective indicators (perfect grammar; mixed registers; "bland"/"robotic" prose; undifferentiated formal prose; transition words in isolation; unsourced content; bizarre wikitext; correct wikitext). Same list on both revisions. - Recorded that `rule-em-dash` and `rule-rule-of-three` remain valid source-page signs (Style / Language and grammar). The em-dash "in combination with other indicators" sentence is a corroboration qualifier, not an Ineffective indicators listing; zero-tolerance stays the house-style default. - Comment-specific indicators retrieved in the same visit: Wikipedia talk-page scope, overlapping existing recorded-only edit-summary entries. No new slugs. - Bumped `ai-slop` 0.3.1 → 0.3.2. Detector, emitter, evals, and rewrite guide are untouched. ## Test plan - `npx markdownlint-cli2` on the two edited markdown files: 0 issues. - `python3` parse of `plugin.json`: version `0.3.2`. - `bash plugins/ai-slop/skills/audit/scripts/detect.test.sh`: all 92 cases passed (roster still exactly 15 script rules). - `scripts/check-changelog-parity.sh --check`, `--check-bump origin/main`, `--check-preserved origin/main`: pass. - `scripts/check-changed-skills.sh origin/main`: PASS, 0 errors. ## Verification Same commands and outcomes as the Test plan. This is a catalog/docs close of a fetch gap, not a detector change; the unit suite is the regression that the 15-rule roster did not move. ## Related - #3032 — the fetch-gap / guardrail question this closes. - #3031 — the contract slice this issue graduated from. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
…ion table `docs/upstream/cursor-pstack.md` claims to be the single source of truth for everything in this marketplace derived from cursor/plugins' `pstack/skills/` collection, and its recheck trigger fires only on a change to a `pstack/skills/<name>/SKILL.md` **named in the attribution table**. `unslop` is a member of that collection and `ai-slop` 0.2.0 (#3031) is derived from it, but the table carried no `unslop` row — so the SSOT claim was false and drift in `pstack/skills/unslop/SKILL.md` would have gone undetected. One row, grounded in what is actually in the repo: the seven catalog entries the Wikipedia inventory did not already carry, the plain-word trio in the shipped vocabulary default, and `reference/rewrite-guide.md` as the home for the upstream file's fix-time half; against the overlap map's deduplication, the Name-dropping and Generic-conclusions exclusions, the calibration measurement that kept abstract metaphor nouns out of the script layer, and the one adding-soul bullet that did not survive. The row says on its face that it was NOT audited at this file's `main@60c641e4` pin: the verdict was formed at integration time against an unpinned upstream `main`, and the catalog's own four-part drift record covers the Wikipedia source page only. The pin is the row's baseline for the next diff, not a claim about the state it was audited at. Not one of the port's ten lanes and it does not claim to be — `ai-slop` 0.2.0 landed before this file existed, so "All ten lanes are decided" is unchanged. Docs-only, outside `plugins/`: no version bump and no plugin CHANGELOG entry. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AqwX2njhiLMWGrMg3QNt4g

No linked issue
Summary
Adds a set of AI-writing tells inspired by Cursor's
unslopskill to theai-slopcatalog, then corrects every claim the plugin made about itself that the shipped code did not actually perform. Also makes the plugin dogfoodable in this marketplace for the first time.Three commits, deliberately kept separate: the first adds the rules, the second corrects what the first over-claimed, the third prunes the task branch's contract slice after graduating its deferred items. The second exists because an exploration and research pass over the first found that its detection half was sound and its documentation, registration, and dogfooding halves were not.
Fix
New detection (commit 1). Three script rules —
rule-chatbot-artifacts(chat-turn residue and sycophancy; IMPORTANT in the severity crosswalk),rule-filler-phrases,rule-stacked-hedging(both SUGGESTION) — each with an argued crosswalk row. Four new rubric tells: false ranges, colon crutches, abstract metaphor jargon, mechanism-free claims.rule-abstract-metaphor-jargonwas deliberately kept out of the script layer on measurement: "substrate" alone had 103 legitimate technical uses in this corpus. Newreference/rewrite-guide.mdowns fix-time guidance, including the guardrail that an em dash must not become a parenthesis or en dash (swapping one tell for another is not a fix).Corrections (commit 2). Four places a document claimed coverage the code does not provide:
recorded-onlyentries that run in neither layer. Header now says "catalogued by", and those rows say they are dormant.rule-vague-attribution, which describes the opposite tell (naming no source, versus naming many with no content). Now recorded as deliberately out of scope for general prose.rule-inline-header-listsboundary refinement was attached to arecorded-onlyentry while the changelog advertised it as live. Now labelled calibration pre-work.Drift guards. All 15 rules' emitted tiers are asserted (was 2 of 15), plus a roster-set check so a rule added to
detect.shwithout a crosswalk row can no longer emit SUGGESTION by silent fall-through. Thetier:frontmatter field and--tierflag are retired fromemit-findings.sh— both owner docs already said this producer omits it, and the flag defaulted to a hardcoded value describing no property of the run.Dogfooding.
.claude/ai-slop.jsondisablesrule-em-dashwith a recorded reason: this marketplace's house style uses em dashes deliberately, measured at 34,999 matching lines across 1229 tracked files. That is a style choice, not a defect backlog. The shipped default stays zero-tolerance.Registration.
ai-slopadded to theconfig-cascadeImplementers table. The surface implemented the full three-layer cascade from its first release and was never tabled, so that table under-reported a conforming surface.Attribution. The upstream inspiration is a single link. The Wikipedia CC BY-SA attribution is unchanged, being a different licence with its own share-alike terms.
Verification
plugins/ai-slop/skills/audit/scripts/detect.test.sh— 84 cases pass, up from 65.scripts/check-detector-findings-crosswalk.sh --check— exit 0, 22 rule rows, every disposition argued from a stated test.scripts/check-contract-slice-prune.sh --check-diff origin/main— exit 0 after commit 3.shellcheck+shfmt -dclean on all three scripts;markdownlint-cli20 issues across 11 touched files;typosclean;jqvalidates both changed JSON files.rule-em-dashfindings alone.Two findings surfaced by verification rather than by review, both fixed here:
disabled=1for a rule the case never mentions. Fixtures now pinHOMEandCLAUDE_PROJECT_DIRto empty directories, the same isolation the suite already applied to inherited git state.Related
rule-em-dashandrule-rule-of-three; blocked here by the research environment's Wikimedia egress denial, not by scope.detector-findingsproducer name the remediation skill its findings need. The real fix for the relay gap; this PR only narrows the claim, since the extension touches three adopters and a consumer.Both were graduated out of this branch's contract slice, which commit 3 prunes per the topic-docs convention.