mirror of
https://github.com/conorbronsdon/avoid-ai-writing.git
synced 2026-09-19 01:32:11 +08:00
docs/codex-commit-attribution
34 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
70975835b5 | chore: publish detector gate CLI | ||
|
|
e79254c892 | fix: prepare CLI package release | ||
|
|
8bbb78d519 | feat: add a zero-dependency CLI for files and stdin (#158) | ||
|
|
66da51290c | fix: treat em dashes as style-only guidance | ||
|
|
28ba61bc9f | fix: preserve prose quote boundaries around malformed bare URLs | ||
|
|
0aa0def0ee | Split canonical skill and ship complete Claude bundle | ||
|
|
3dd72f5ec6 | Fix automatic marks inference and malformed link scanning | ||
|
|
0ffc4e688a | Merge remote-tracking branch 'upstream/main' into fix/issue-104-deterministic-marks | ||
|
|
f1fab30895 | Add deterministic quote normalization with shared Markdown protection | ||
|
|
c5ec5b8a93 | Complete catalog clarity rules with source-preserving guidance | ||
|
|
081b495614 | Narrow repeated reversal punchlines and integrate current main | ||
|
|
788c6675c1 |
Bring Avoid AI Writing to ChatGPT and Codex (#135)
* feat: seed OpenAI plugin skill resources * feat: add OpenAI plugin manifest and public metadata * feat: add routed ChatGPT and Codex skill graph * test: add OpenAI plugin validation and submission pack * fix: correct listing character-count evidence * feat: add typed cross-skill handoff contract * docs: encode agency review lenses for orchestration * feat: add machine-validated typed skill graph * feat: upgrade router to typed orchestration protocol * feat: connect detector to typed handoff network * feat: connect rewriter to verification and representation guards * feat: add typed file-edit handoffs and repair loop * feat: make preservation verifier a blocking typed gate * feat: connect interpretation guardrail to evidence handoffs * refactor: replace legacy yaml graph with validated json graph * test: validate skill graph and cross-skill contracts * ci: validate cross-skill orchestration graph * refactor: package connection validator inside router skill * refactor: keep connection validator inside packaged router skill * ci: run packaged connection validator before and after extraction * docs: align routing matrix with typed graph * test: expand routing evals for connected skill graph * fix: remove unintended reviewer detector cycle * fix: make interpretation reviewer terminal in skill graph * test: reject terminal outgoing edges and unbounded graph cycles * docs: align handoff contract with terminal reviewer semantics * docs: route fresh interpretation evidence through router * docs: document graph v2 and connection validation * fix: route fresh detector requests through orchestrator * test: enforce agency lenses and router-return semantics * test: cover terminal reviewer return-to-router flow * docs: add connected skill graph v2 to release notes * fix: remove unsupported skill policy products * fix: remove unsupported skill policy products * fix: remove unsupported skill policy products * fix: remove unsupported skill policy products * fix: remove unsupported skill policy products * fix: remove unsupported skill policy products * fix: remove unsupported skill policy products * fix: align plugin validator with graph v2 and ingestion policy * fix: synchronize bundled detector and verifier resources * fix: bundle detector beside preservation validator * ci: watch canonical detector resources for plugin drift * test: smoke packaged preservation residual detector * ci: exercise residual detector before and after packaging * fix(port): sync ChatGPT/Codex plugin version with canonical SKILL.md The merge with main moves the canonical skill to 3.28.0; the plugin manifest, listing, and submission pack still carried 3.25.1, so scripts/sync-plugin-skill.sh and scripts/validate-openai-plugin.py both exit 1 on the effective merge. Bump the three manifests and regenerate the copies the sync script owns. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(port): publish the plugin from the canonical repository Every public destination in the ChatGPT/Codex package pointed at the contributor's fork: websiteURL, privacyPolicyURL, termsOfServiceURL, homepage, repository, the submission listing, and SUPPORT.md. After a merge the canonical owner would not control the published legal and support pages. Point them all at conorbronsdon/avoid-ai-writing and make developerName/packagePublisher the identity that will be verified in the OpenAI portal. Packaging credit stays: NOTICE.md and listing.json now name the contributor explicitly. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(detector): CRLF input no longer bypasses the preservation validator validate() extracts frontmatter, tables and headings with regexes that anchor on a bare newline. A CRLF document matched none of them, so changing 'title: one' to 'title: two' in Windows-formatted frontmatter returned { ok: true, errors: [] }. This is a pre-existing bug in the canonical detector, not something PR #135 introduced - the bundled plugin copy is byte-identical to detector/validate.js - so the fix and the must-fire fixtures go in the canonical source and the generated copy is re-synced from it. Adds four CRLF fixtures to detector/validate.test.js; all four fail against the unpatched validator. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(port): make the manifest the only source for listing metadata submission/listing.json restates twelve manifest fields and only three of them were asserted, so the listing could ship a different developer name, support URL or description than the manifest it claims to describe - which is exactly the drift that put a fork's URLs into the public package. Assert every duplicated field against .codex-plugin/plugin.json, derive the hand-maintained character counts instead of trusting them, and require every public URL to sit under the canonical author.url so publication cannot move off this repository without turning the check red. Also: guard the canonical-copy comparison against a missing plugin copy (it raised FileNotFoundError instead of reporting), scope the hygiene scan to the packaged surface instead of walking .git, and restore the CLAUDE.md path-filter rationale the port deleted from the workflow. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(port): bundle every resource the canonical skill references OpenAI's submission contract says each skill must include any referenced scripts, templates, or assets, and the Codex skill layout has no shared- resource mechanism, so skills/avoid-ai-writing/SKILL.md (byte-identical to root SKILL.md) now ships with synced copies of detector/patterns.js, detector/validate.js, detector/CATEGORIES.md, scripts/check-style.js, and examples/ at the same relative paths. scripts/sync-plugin-skill.sh produces them and the existing regenerate-then-diff CI gate covers them. A new smoke test runs check-style and the preservation validator from inside the bundled tree and from an extracted package. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(port): manifest supportURL, ancestry-checked baseCommit, policy.products interface.supportURL now lives in .codex-plugin/plugin.json and the listing value is validated against it. Both submission files record baseCommit as the origin/main merge-base and the validator checks it is an ancestor of HEAD so it cannot drift silently; the verifier's copied patterns.js joins the deterministic-resource inventory. The validator accepts policy.products with CHAT and/or CODEX per the current agents/openai.yaml schema and keeps rejecting unknown policy keys, with tests. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(port): follow main to 3.29.0 after #128 landed Bump .codex-plugin/plugin.json and the submission metadata to 3.29.0, set baseCommit to the new origin/main merge-base, and regenerate the bundled copies so the sync gate is clean on the merge ref. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(port): changelog and README for the plugin package; harden packager and validator Qodo re-review items: a dated 3.29.0 changelog entry and a README section for the native ChatGPT/Codex package; the packager and validator now reject symlinked top-level package files; JSON loading rejects a non-object root with a validation error instead of crashing, with tests for list and null roots and for the symlink case (skipped where symlinks need privileges). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(port): packager and validator hardening, lone-CR preservation, workflow paths Qodo re-review items 6-11: the marketplace policy no longer demands install-time authentication for a skills-only package (ON_USE, the only other documented value); the packager rejects an output path that is a packaged input or sits inside an included directory and fails on a missing top-level package file instead of silently omitting it; the validator type-checks nested submission objects before access; the preservation validator normalizes CRLF only, so a lone carriage return changed inside code is reported again; LICENSE joins the workflow path filters. Tests for each; bundled validator copies re-synced. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(port): marketplace authentication policy is first-use, not install-time The skills-only package has no authentication flow or hosted service. The marketplace docs say policy.authentication decides whether auth happens on install or first use; first use never triggers for local skills, so ON_USE replaces ON_INSTALL. (Qodo item 6, deferred from the previous commit because the implementer sandbox could not write .agents/.) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(port): graph validator rejects malformed JSON cleanly; canonical URL is a constant Qodo items 8 and 9. validate_connections.py now checks the graph root and edge field types and reports through its validation path instead of raising, with a test script wired into CI. validate-openai-plugin.py pins CANONICAL_PROJECT_URL and requires author.url to equal it, so changing every public URL to a fork no longer passes; test added. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(port): bound SVG parsing and stop empty skill names polluting the graph set Qodo items 19 and 20. The validator rejects SVGs carrying <!DOCTYPE or <!ENTITY declarations and anything over 256 KiB before handing text to ElementTree, closing the entity-expansion path; a skill whose frontmatter lacks a name reports that error once instead of inserting an empty name that cascades into router-graph errors. Tests for both. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * ci(port): full-history checkout so the baseCommit ancestry check can run The validator's merge-base --is-ancestor check needs the base commit in the checkout; actions/checkout's default depth of 1 made CI report it as "not a valid commit name". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Conor Bronsdon <120674402+conorbronsdon@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
d8c235186f |
Add detector trio from #108: launch intros, crowd contrast, fake-casual props (#128)
* Add detector trio from #108: launch intros, crowd contrast, fake-casual props Three regex-detectable patterns from the welttowelt merged-system diff, each with a must-fire and a must-not-fire fixture: - launch-intro: sentence-initial imperative product introductions ("Enter X.", "Meet X, your new...", "Think X meets Y"). "Say hello to X" stays judgment-only ("Say hello to Grandma." is ordinary prose). - crowd-contrast: the trailing "while everyone else..." clause, gated on a dismissive verb so literal simultaneity never fires. - fake-casual-prop: stage directions, wink asides, and "because of course it does". Verdict closers and label-prefix openers stay LLM-judgment per the precision-over-recall policy. Catalog 62 -> 65, engine 48 -> 51, word table unchanged at 112. * Apply review fixes to the #128 detector trio Addresses the three detector-surface items in the CHANGES_REQUESTED review, plus the prose-scoping follow-up comment. Each item was reproduced against the PR head before being changed. 1. `launch-intro`: the bare `Enter X.` surface is judgment-only. It matched "Enter Password." and "Enter Amount." verbatim, and "Enter Username — your work email." through the dash terminator; neither a terminator change nor a field-name denylist reaches the period-terminated class. The `Meet X, your new favorite…` and `Think X meets Y` surfaces stay. The three UI forms and "Enter Flowdesk." are pinned as must-not-fire. 2. `crowd-contrast`: the progressive branch is restricted to `-ing` forms. `(?:e|es|ed|ing)` let the adjective ("was still deliberate about"), the passive ("was still debated by pundits") and the bare present through; all three are now must-not-fire fixtures. 3. `fake-casual-prop`: `because of course …` is judgment-only. The present tense plus `did` gate does not hold — "The build failed because of course it did." is the ordinary human grumble in the same form. Two grumbles are pinned as must-not-fire. Also scopes the prose claim: the "was still" marker gates the debate/speculation branch only, and the two stereotyped variants ("wrote think-pieces", "played catch-up") match on their own wording. SKILL.md, detector/CATEGORIES.md and the CHANGELOG say the same thing, and the generated plugin/cursor copies are regenerated from SKILL.md. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Disclose the crowd-contrast residue that was measured, not assumed Beyond the review. A fresh-eyes pass turned up sentences that fire and that the entry's disclosure did not cover; every one was reproduced against this branch before being written down. - Branch one fires on any literal progressive use of its verbs, not only on "was still debating": "while the market was still speculating about the price" and "while others were still arguing about procedure" are ordinary wire copy and both fire. - Branches two and three fire on literal contrasts of their own: "while everyone else wrote think-pieces from Washington" (a real reporting contrast) and "while everyone else played catch-up in the spring" (sports and classroom narrative). - The wink-aside regex accepts all four of (yes|no) x (really|seriously); the entry named two. No regex changes: these are accepted under precision-over-recall, and narrowing them is the maintainer's call, not a review item. The prose now states what the engine does instead of a tighter gate it does not enforce. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Tighten two surfaces and make every entry state what its regex does Cross-family review (Codex / GPT-5.6). Each item was reproduced against `land-pr-128` before the change and re-measured after. Regex changes, both false positives on ordinary prose: 1. `fake-casual-prop`: `chef['’]?s\s+kiss` made the apostrophe optional, so "At midnight, *chefs kiss* their spouses goodbye" fired. The apostrophe is now required, straight or curly. 2. `launch-intro`: `the\s+new\s+(?:standard|way|home)\b` let the head noun swallow the first word of a compound noun — "Meet Rosa, the new home secretary" and "Meet Emma, the new way station manager" both fired. Each head now needs the tail launch copy actually has (`home of`, `way to`, `standard in|for`) or an end of clause. "Meet Riverside, the new home of our Saturday farmers market." still fires. Not changed, disclosed instead: "Meet Alice, your new favorite aunt" and "Think Alice meets Bob at noon" fire. They are person-name variants of the two surfaces the maintainer asked to keep, so narrowing them would cost the surfaces themselves. Test change: the `(yes, really)` positive shared a fixture with `*checks notes*` and only asserted that some `fake-casual-prop` existed, so replacing the wink regex with a never-match left it green. It is now an independent case asserting the matched text. Prose: the three entries and the CATEGORIES rows now state the actual gates — the four `Meet` heads and the one-token 2-30 character name; the `was|were|is|are` + `still` + `-ing` branch, the `writing|wrote` branch and the `play|plays|played|playing` branch; the six stage directions and four parentheticals — plus the measured misses that follow from closed lists: two-token names ("Meet North Star", "Think Google Docs meets Microsoft Word"), crowds outside the list ("every competitor", "our rivals"), and register neighbours ("*checks calendar*", "(yes, honestly)"). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: welttowelt <welttowelt@users.noreply.github.com> Co-authored-by: Conor Bronsdon <120674402+conorbronsdon@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
3bd64f19f4 |
Add seven rhetorical-tic categories from Simon Willison's LLM cliché highlighter (#138)
* Add seven rhetorical-tic categories from Simon Willison's LLM cliche highlighter Three with detector types (performed-insight, negation-chain, dev-blog-boilerplate) plus fixtures; four as skill-only judgment rules with reasons recorded in CATEGORIES.md. Counts bumped per the CI contracts (69 pattern categories, 51 engine types); version 3.28.0. * Address review: sync 3.28.0 release artifacts, narrow detector precision - Bump package.json, plugin.json, and regenerate the bundled skill and cursor rule (plugin-skill-sync now passes locally). - negation-chain: the no-chain must open its sentence (mid-sentence inventories stay clean); the did-not chain is comma-joined with the subject elided (sequential narration stays clean). - performed-insight: sit-with requires a boundary or 'for a moment' after that/this; the 'only X I trust' branch is dropped; sentence- initial 'Turns out' uses a lookbehind so the issue text and index no longer consume the previous sentence boundary. - dev-blog-boilerplate: 'it just works' no longer matches the phrasal 'it just works out'. - Must-not-fire fixtures added for every reproduction in the review, plus a text/index regression assertion for Turns out. * Narrow rhetorical-tic detector precision * Align narrowed detector docs and slogan coverage --------- Co-authored-by: tech nasty <262050521+t3chnaztea@users.noreply.github.com> Co-authored-by: Conor Bronsdon <120674402+conorbronsdon@users.noreply.github.com> |
||
|
|
4e79a67871 |
feat: add rendered Markdown source mode (#137)
* feat: add rendered Markdown source mode * fix: address rendered Markdown review regressions * fix: close rendered HTML comments before code masking --------- Co-authored-by: Conor Bronsdon <120674402+conorbronsdon@users.noreply.github.com> |
||
|
|
40328bd292 |
docs: restrict edit mode to prose files (#136)
Co-authored-by: Conor Bronsdon <120674402+conorbronsdon@users.noreply.github.com> |
||
|
|
0bdab7bfbb |
docs: document npx skills as a universal install method (#131)
* docs: document npx skills as a universal install method Points users at vercel-labs/skills (npx skills add) as the fastest way to install this skill into any of its 75+ supported agents, with npx skills update covering future updates. Existing manual per-platform steps stay as a no-Node fallback. * address review feedback: pin npx version, dedupe count, add changelog entry - Pin npx skills invocations to @latest explicitly and note it runs third-party code, with a pointer to pinning a specific version instead. - State the "75+ agents" figure once instead of in two places. - Add the 3.25.1 CHANGELOG entry this repo's conventions expect for a notable change, even though no rule/detector content changed. * address maintainer review: pin skills@1.5.23, fix behavior claims, add repository field - Pin npx invocations to skills@1.5.23 instead of @latest for a reproducible install, and note the CLI's Node >=22.20.0 requirement. - Correct the install description: for a root-level skill like this one, the CLI's GitHub blob fast path installs SKILL.md only, not the whole repo (per vercel-labs/skills src/blob.ts). git clone remains the documented route for the detector, tests, and other repo tooling. Drops the now- redundant raw-SKILL.md-URL example since the shorthand does the same thing. - Correct the update description: skills update prompts for project/global scope and refreshes the selected scope, not every install across both. - Add metadata.repository to SKILL.md's frontmatter so a copy installed via the SKILL.md-only fast path still links back to the project. Synced to the plugin copy via the existing sync-plugin-skill.sh. * fix: vary sentence structure instead of repeating em-dash appositive Self-audit with the avoid-ai-writing skill flagged the same "clause — appositive clause" shape used six times in ~600 words across the new Quick Install prose. Split into separate sentences, semicolons, and commas as appropriate, keeping one dash for genuine variety instead of zero. * docs: clarify skills CLI install behavior --------- Co-authored-by: Conor Bronsdon <120674402+conorbronsdon@users.noreply.github.com> |
||
|
|
ca2206c2f5 |
Bind voice-profile targets to Never-inject guardrails (fixes #100) (#133)
* Bind voice-profile targets to Never-inject guardrails (fixes #100) * fix-ups for #133: sync generated copies, changelog, and formatting - drop the unrelated Dockerfile - give the guardrail intro line its own paragraph (leading space folded it into the previous one) and fix the professional-profile comma splice - bump plugin.json to 3.25.1 and regenerate the bundled plugin skill and cursor rule via the sync scripts - add the 3.25.1 changelog entry crediting @mahinNadir npm test green (39/39 check-style, full suite passes). --------- Co-authored-by: Conor Bronsdon <120674402+conorbronsdon@users.noreply.github.com> |
||
|
|
6f77e683cf |
Add catalog-only entries from #108: false agency, transformation crutch, domain-term collision
Judgment-only rules per the precision-over-recall policy, with the
carve-outs written as operative entry text per review:
- False agency: literal verbs and collective-actor shorthand ("the
market rewards shipping") are protected in the entry itself.
- Transformation crutch: literal and mechanism-stated transformations
stay unflagged.
- ZK/crypto domain-term collision ships as two genre-scoped Tier 3
phrase rows (skipped by the deterministic engine); the cross-genre
generalization is held as a note.
- "This matters because" joins the persuasive-authority tropes;
the concession-fragment reassurance pair joins manufactured
punchlines.
Catalog 65 -> 67, README Tier 3 phrase count 10 -> 12; engine stays
at 51, word table at 112.
|
||
|
|
7b5fdc73b2 |
Add detector trio from #108: launch intros, crowd contrast, fake-casual props
Three regex-detectable patterns from the welttowelt merged-system diff,
each with a must-fire and a must-not-fire fixture:
- launch-intro: sentence-initial imperative product introductions
("Enter X.", "Meet X, your new...", "Think X meets Y"). "Say hello
to X" stays judgment-only ("Say hello to Grandma." is ordinary prose).
- crowd-contrast: the trailing "while everyone else..." clause, gated
on a dismissive verb so literal simultaneity never fires.
- fake-casual-prop: stage directions, wink asides, and "because of
course it does". Verdict closers and label-prefix openers stay
LLM-judgment per the precision-over-recall policy.
Catalog 62 -> 65, engine 48 -> 51, word table unchanged at 112.
|
||
|
|
3c0fd8a266 |
Add actually as a cut-first writing signal (#126)
Co-authored-by: Codex <codex@openai.com> |
||
|
|
46087cea58 |
feat: detect unnecessary hyphenation (#120)
* feat: detect unnecessary hyphenation * fix(detector): harden hyphenation masking * fix(detector): mask long path components * fix(detector): keep zero-weight copyedits out of AI highlights buildSentenceRegions() mapped every text-bearing issue into highlight_sentence_for_ai, so a copyedit-only document scored 0 and classified HUMAN_ONLY while still reporting an AI-highlighted region. Rename SUMMARY_ONLY_TYPES to NON_HIGHLIGHT_TYPES, since the set now covers both anchorless summary signals and anchored style-only findings, and add unnecessary-hyphenation to it. The finding stays in issues[] at P2 with its weight of 0; scoring and trinary classification are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UrhAmTQkVxzX6UkmTL2TCf --------- Co-authored-by: Conor Bronsdon <cmbronsdon@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
a575602b3d |
release: 3.23.1 — constructor false-positive fix, automated npm publishing (#117)
Version bumped across all five sites (SKILL.md, plugin copy, plugin.json, package.json, cursor rules regenerated via the sync scripts). First release through the guarded publish pipeline from #113. Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
f666087e52 |
feat: optional --style house-style layer (config-driven, points at Vale) (#99)
* feat: optional --style house-style layer (config-driven, points at Vale) Implements the config-driven design recorded in #88, which #76 and the fork review converged on. No bundled guides: the layer applies register/voice directives and removes AI tells on top of whatever mechanics you enforce. --style ./house.json applies a user-supplied JSON config (register + mechanics) and scripts/check-style.js verifies the CHECKABLE mechanics deterministically: quotes and latinAbbrev gate the exit code (0 clean / 1 hard / 2 tool error), headings, emDash and spellNumbersUpTo are advisory, serialComma is never checked. The docs scope the verb accordingly rather than claiming "mechanics are verified" flatly. examples/ ships two generic, guide-neutral starters plus the schema, and links #88 for the licensing rule. A bare --style "APA" is a best-effort fallback, not a feature: SKILL.md instructs the model to print a no-compliance-claim status line and not to reproduce the guide's text. Those are instructions rather than checked rules, and the docs say so instead of asserting the behaviour as fact. --style is listed in the SKILL.md invocation line and has an explicit composition rule with --voice/--context, since the file specifies composition for every other axis. README: the "House style is a different job" section said "There's no --style input", which this makes false. The first paragraph now describes the config input and reconciles with the heading (enforcing a PUBLISHED guide is the different job). The Vale paragraph and the heading anchor are unchanged. cursor-rules: the ported rule would have told a Cursor user to run scripts/check-style.js and read examples/, neither of which ships in the .mdc. Two anchored spans in sync-cursor-rules.sh rewrite those the way span 3 already handles detector/validate.js, so the port stays self-contained. Worth noting the drift guard only covers edits to anchored spans, not newly added SKILL.md sections that introduce repo references. The checker went through three adversarial review rounds, and each round found the previous round's fix had introduced a new way to hard-fail a correct document or to miss a real one. The tests pin all of them: markdown link titles, reference definitions (including escaped quotes in a title), HTML attribute values, nested and tilde fences, BOM'd frontmatter, URLs containing parentheses, parentheticals that wrap or span a code block, and a stray "(" that must not suppress later findings, and prose containing a comparison ("n<N ... >") that must not be mistaken for an HTML tag. Masking runs refdef -> links -> tags, in that order, because masking a link destination first makes an ordinary "[a](url): text" line look like a reference definition. Link masking walks to the matching paren and scans linearly; the regex form was quadratic (22.7s on a hostile line, now 4ms). resolveConfig decides path-vs-name by shape so a cwd file can't shadow a bundled example, the CLI parses by position, a config with "mechanics": null or [] exits 2 rather than a false-green 0, and advisory findings print instead of hiding behind --json. Version 3.22.3 -> 3.23.0 in SKILL.md frontmatter, package.json and plugin.json; CHANGELOG entry under a dated heading; plugin and cursor copies regenerated. No detector changes: catalog counts unchanged (61 / 112). 32 tests in scripts/check-style.test.js under npm test; detector-test.yml path filters extended to scripts/** and examples/**. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * style: mask indented code, tighten frontmatter open, announce the resolved mode Review fixes applied on top of the submitted branch: - Indented code blocks (4+ spaces / tab after a blank line, outside a list) are masked, so pasted terminal output can't hard-fail a correct document. Lazy continuation and list-item content stay checked; a code block nested in a list item needs a fence. Was the largest undocumented false positive. - A document opening with a thematic break is no longer read as frontmatter (which silently swallowed everything to the next ---). - The bare-name traversal regex was dead code its test never reached; a bare name is a single path segment by construction, so the guard is now a comment stating that argument, and a test pins dot-bearing names. - Config runs open by naming the resolved config, mirroring the fallback's status line, so which of the two modes ran is always explicit in output. - Known-limitations lists gain the double-backtick span and next-line reference-definition title gaps; examples/README.md joins the self-scan budgets; CHANGELOG updated; cursor-rule anchors follow the SKILL.md edit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Conor Bronsdon <120674402+conorbronsdon@users.noreply.github.com> |
||
|
|
5897f7b497 |
skill: close five prose-contract gaps flagged in downstream review (#97)
* skill: close five prose-contract gaps flagged in downstream review All five from the cubic review on davila7/claude-code-templates#773. Prose only: no rule, threshold, or detector changes. Tables join the edit-mode flag-don't-fix list (matching what validate.js already enforced), the rewrite job line scopes 'all AI-isms removed' to editable ones, edit mode gets an explicit instruction boundary, the tracking-parameter fix leaves the rest of the query string alone, and the second-pass audit must say when it supersedes section 2. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * review: close the gaps the clarification pass itself opened Adversarial pre-merge review caught four: two validate.js header comments quoting the pre-fix sentences verbatim (refreshed, comment-only), an 'only the listed parameters' exclusivity claim that contradicted AI_URL_PARAMS and ai-utm-source coverage (reworded), and seven stacked 'X, not Y' contrastive negations on one line where the file's previous maximum was two (three rewritten as direct positives). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
ae1ecbebf0 |
detector: stop counting non-tag "#" forms as hashtags (#90) (#92)
* detector: stop counting non-tag "#" forms as hashtags (#90) hashtag-stuff counted every #word and flagged at six, so a paragraph citing six issue numbers scored as a stuffed tag block. Found when this repo's own README linked issue #88 and the detector flagged the README. The bug report cannot be written without triggering the bug either: the prose of #90 scores hashtag-stuff on its own issue references. Two subtractive changes, so the rule cannot start firing on anything it does not already fire on. maskCode() blanks fenced blocks and inline code spans, index-preserving, before counting. fenceRanges() already existed but was wired only to title-case-header, so a tag quoted in backticks counted as a tag used. Fences are blanked before inline spans so a fence backtick cannot pair with a later span and swallow the prose between them. isSocialTag() subtracts forms that cannot be a tag: all-digit (#88), hex colours of 3/4/6/8 digits, and C preprocessor directives. owner/repo#88, URL fragments, shebangs, and Markdown headings already passed on the rule's own anchor and are untouched. Deliberately still counted: #main and #general. A CSS id, a channel, and a tag are the same token. The only separator is an adjacency gate, and measuring it showed it also stops the rule catching inline tag stuffing, which is a real shape. Accepted cost of the hex carve-out: an all-hex word tag (#dad, #cafe) stops counting, which only changes an outcome if five real tags sit beside it. Six fixtures: four that must not fire, two that must, per CONTRIBUTING. Mutation-tested both halves -- disabling isSocialTag kills 3 tests, disabling fence masking kills the suite. No new detector type, so CATEGORIES.md is unchanged and the pattern count stays 61. Gates green: npm test, check-pattern-count 61/112, self-scan SKILL.md 12/25, sync-plugin-skill 3.22.1. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> * Address adversarial review: a false negative, fake coverage, and no version bump Three real problems, one of them worse than the bug being fixed. The hex carve-out covered 3- and 4-digit forms, which silently deleted them cost true positives on exactly the stuffed-block shape the rule exists to catch -- two verified blocks that flagged on main went silent. Trading a false positive for a false negative is the wrong direction in a repo whose stated bias is precision over recall. Narrowed to 6 and 8 digits. Real palettes are dominated by 6-digit values, so the CSS paragraph still lands under the threshold without the short forms. The fixture named for inline-code masking did not test it. Four of its six spans quoted forms isSocialTag already subtracts, so with masking deleted the count was 3, under the threshold, and the test passed. Rewritten with six spans that all survive the carve-outs. No CHANGELOG entry and no version bump on a behavior change to an engine downstreams vendor byte-identical. Two different patterns.js byte-streams would both have called themselves 3.22.1. Now 3.22.2 across package.json, SKILL.md frontmatter, and plugin.json, with an entry that records the two recall changes (unclosed fence, stray backtick) rather than only the win. Also mask indented code blocks. A fence nested in a list item is indented past the three spaces fenceRanges anchors, so a README config block still counted -- the exact shape masking was added for. Mutation-tested all nine mutants now killed, including the inline-masking one that previously survived: remove inline / fence / indented masking, isSocialTag always true, drop digit / hex / cpp carve-out, widen hex to 3-8, threshold 6 to 7. Gates green: npm test, self-scan:check (SKILL 12/25, CHANGELOG 29/40), check-pattern-count 61/112, sync-plugin-skill 3.22.2. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> * Third review pass: drop the indented-code pass, and stop eating a-f words Two false negatives and one artifact that never got the correction. SKILL.md still said CSS hex colours "(#fff, #1a2b3c)" are subtracted. The narrowing to 6/8 digits landed in patterns.js and in the CHANGELOG and never traveled to SKILL.md -- the file agents load and downstreams vendor. Verified wrong: seven 3-digit colours still flag. This is the same shape as the two claims the first review pass caught, arriving a third time through a different door. Dropped the indented-code masking pass entirely rather than patching it. Four spaces is a code block only at top level; under a list marker it is a paragraph continuation, so blanking it silenced real tag blocks: - We shipped the detector ... (blank) #AI #Innovation #FutureOfWork #MachineLearning #Leadership #Growth flagged on main and went silent on the branch. #90 reports fences and inline spans; the indented pass was scope I added in response to review pass two, and it was the sole source of eleven surviving mutants including a real off-by-one in its offset arithmetic. Deleting it removes the arithmetic and the state machine with it. HEX_COLOUR now requires at least one digit. #decade, #facade, #deface and #beaded are 6-8 char a-f words and real tags; every actual palette value carries a digit. Same defect class as the 3/4-digit carve-out the last pass removed, one size up, and not eliminated by that fix. Fixtures for both regressions plus an 8-character RGBA case, which was the one genuine coverage hole left: dropping the {8} alternative used to survive. Two mutants remain undistinguishable (inline pass reading text vs withoutFences, and an inclusive blank boundary); I probed for inputs that separate them and found none, so they are equivalent rather than uncovered. Gates green: npm test, self-scan (CHANGELOG 29/40), check-pattern-count 61/112, sync-plugin-skill 3.22.2. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
8042712580 |
detector: derive the engine type count instead of restating it (#91) (#93)
* detector: derive the engine type count instead of restating it (#91) TYPE_LABELS has 47 keys. Six places said 45 or 46: both README count lines, both CATEGORIES.md count sentences, the patterns.js header, and the package.json description that ships to npm. Three of the four commits that added a type edited README.md in the same commit and still left the number alone. That is the argument for a guard rather than a convention: the count sits inside a 90-word parenthetical explaining why two counts deliberately differ, so it reads as prose and survives editing. |
||
|
|
6948cdb91b |
package: version had drifted six releases behind the skill (#79)
package.json said 3.16.0 while SKILL.md frontmatter and the CHANGELOG both said 3.22.1. The package is not published, so nothing downstream was wrong yet -- but publishing would have put 3.16.0 metadata on npm permanently against 3.22.1 code, and npm versions cannot be rewritten. Caught while preparing the first publish. This is the failure mode ssot-check exists for, on a fact this repo owns. Suite green: detector, categories, validate, corpus. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
fba57d3c38 |
Enforcement, self-scan proof, and the first measured accuracy numbers (v3.22.0) (#68)
Adds a preservation validator, a self-scan with PROOF.md, over-correction guardrails, a false-positive intake, and a two-class control corpus with the project's first FPR, TPR, and AUC. Splits Tier 1 into 1A frequency markers and 1B clarity edits, and fixes two detector defects the measurement found (#67, #69). Findings and open decisions: #70, #71, #72, #73. |
||
|
|
53ae05a88e |
v3.16.0: add "load-bearing" (metaphor) to Tier 1 (#55)
Adds metaphorical "load-bearing" as a Tier 1 phrase — an LLM tell for labeling any dependency an argument rests on ("load-bearing assumption/claim/invariant"). Matches the hyphenated compound only; unhyphenated "load bearing" is ordinary English.
Construction carve-out exempts attributive use before a literal structural noun (wall, beam, column, joist, truss, member, footing, slab, stud, partition, masonry, lintel, pier, rafter, girder, capacity), with an optional material/position adjective in between. Abstract-capable nouns (structure, element, frame, foundation) are excluded so the metaphor still fires on "the load-bearing structure of his argument".
Known gap: predicative use ("the wall is load-bearing") still flags — the tell lives in the subject, which a lookahead cannot reach. Carve-out design tracked in #56.
Sources: Marek Suppa, Yaniv Bernstein, Developers Digest, HN 48905248, r/ClaudeAI.
|
||
|
|
500ff59006 |
v3.15.0: conversational-register patterns (wall-of-text, recap-flattery) (#53)
* v3.15.0: conversational-register patterns (wall-of-text, recap-flattery) Adds three catalog entries prompted by a real-world GitHub issue exchange where a maintainer called out an assisted-sounding reply with "I prefer to talk human to human" (name/repo withheld): - Wall-of-text replies: reply-length text delivered as one unbroken paragraph with no line breaks, where humans in conversational registers break at thought boundaries instead. Documented as an LLM-judgment rule after a first-pass detector implementation broke an existing calibration fixture and, on review, would have fired on any ordinary short paragraph rather than anything AI-specific. - Recap-flattery opener: summarizing the reader's own work back at them with praise before getting to the point. LLM-judgment rule. - Immaculate typography in casual registers: folded into the existing Formatting section at the same weak-signal tier as curly quotes, plus its inverse (preserve a human's typos when editing their casual text). Catalog goes from 51 to 53 detection categories; the deterministic engine stays at 45 types (no new type — see the CATEGORIES.md §C note and the NOTE in patterns.js for why the detector attempt was reverted). Also catches the Cursor port up from v3.12.0 to v3.15.0, closing a gap where it had missed the 3.13.0 and 3.14.0 rule changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Review fixups: recap-flattery dedup line + wall-of-text carve-out Two neighbor-standard gaps found in adversarial review of the new conversational-register rules: - Recap-flattery opener now explicitly distinguishes from Sycophantic tone and Acknowledgment loops (every adjacent category carries a "Distinct from X" clause; without it the skill's audience would file dupes against those two). - Wall-of-text replies now carries an explicit legitimate-use carve-out (a single dense paragraph is correct in blog/docs/formal registers), per CONTRIBUTING's precision-over-recall rule. Notes why a tolerance matrix row is the wrong scoping home: a plain issue comment auto-detects to the `blog` profile, so a skip-on-blog cell would suppress the rule in the exact register it targets. Ported to cursor-rules/.mdc and synced to the plugin copy. Contracts still green: npm test (45 detector types), pattern count 53. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
46d3a8aaba |
Fix package.json version drift (3.5.0 -> 3.14.0) (#51)
package.json's version field hadn't been bumped since the 3.5.0 release (2026-05-27) even though CHANGELOG.md, the git tags, and the plugin manifest (plugins/avoid-ai-writing/.claude-plugin/plugin.json) have all advanced to 3.14.0. The new CHANGELOG-driven release workflow (.github/workflows/release.yml, #50) already flags this as known, non-blocking drift in its warning step — this closes that gap. Also fixes the adjacent stale "44-category" description, which predates several category additions; the detector's own CATEGORIES.md contract test currently pins the engine at 45 types. No code consumes package.json's version programmatically (not published to npm; release.yml reads CHANGELOG.md as the source of truth and only warns on mismatch). Verified npm test, scripts/check-pattern-count.sh, and scripts/sync-plugin-skill.sh all still pass after the bump. |
||
|
|
4331560d02 |
Detect social endorsement closers (#29) (#30)
* Add social endorsement closer detection (#29) LLMs commonly close LinkedIn/X share posts with a generic curatorial sign-off teeing up a link — "This one is worth your time:", "Do yourself a favor and read this", "Thank me later". The endorsement is demonstrative-anchored and could sit under any link, which is the tell. - New detector `type` social-cta-closer (engine 43 → 44 types), weighted like formulaic-opener (8) so the length divisor doesn't wash it out on a short post. Severity high (P1). - New SKILL.md "Social endorsement closers" section (catalog 47 → 48), plus P1-list and tolerance-matrix rows (strict on linkedin). - Demonstrative anchors ("this one", "do yourself a favor", "won't want to miss") keep it off plain human endorsements ("the book is worth reading, but the middle drags"). Distinct from the bare "worth [verb]ing" word-table entry and from infomercial mid-flow hooks. - Tests: 3 fixtures (LinkedIn share post, bare-CTA variants, human-prose negative). Mirrored into cursor-rules + synced plugin skill; counts updated across README/CATEGORIES/package.json; version 3.8.0 → 3.9.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Harden social-cta-closer regexes against review findings Two-agent review (code-reviewer + test-analyzer) found that 6 of the 10 closer patterns dropped their anchor and fired on ordinary prose, and that the contraction branches missed curly apostrophes — so the detector skipped the exact "you won't" form its own docs ship as the canonical example (LinkedIn/Word/macOS auto-curl to U+2019). Precision fixes: - Apostrophe classes now admit U+2019 across every contraction branch (won't / don't / can't / one's / you'll), matching the house style of the existing smart-punct detector. - "do yourself a favor and read THIS/IT" — gated to a demonstrative object, so "...read the runbook" no longer matches. - "miss this" / "bookmark this" — trailing-terminal lookahead, so the closing-line shape fires but "miss this meeting" / "bookmark this page" don't. - "thank me later" / "save this for later" — sentence-initial lookbehind (kept match text clean), so "she will thank me later" / "I usually save this for later" don't. - "trust me, ..." — dropped the bare "this one" branch that caught "trust me, this one took all afternoon." Tests: branch-coverage fixture (one positive per regex so a typo fails loudly), a curly-apostrophe fixture, and a 7-case literal-prose negative table built from the reviewers' false-positive probes. 66 checks green; count + plugin-sync gates pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
2b38cd7ae2 |
Make repo SSOT for the detection engine (#16)
* feat: make repo SSOT for the detection engine Extract the 43-category detection engine + its dependency-free node test harness from the (winding-down) private web-app repo into detector/, so this open-source repo is now the canonical source of truth for both the rules (SKILL.md) and their executable expression (detector/patterns.js). - detector/patterns.js: zero-dep, build-step-free, runs in node>=18 + browser - detector/patterns.test.js: 60 fixtures, no deps (node:assert) - package.json + CI: `npm test` on push/PR touching detector/ - detector/CATEGORIES.md: anti-drift map of SKILL.md sections <-> detector types - README: "Run the detector" section The cert/attestation/x402/token layer stays behind in the private app; the engine is a pure function with no knowledge of it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: reclassify smart-punct-signature as a partial skill map Community PR #15 adds a curly-quotation-marks rule under SKILL.md's Formatting section, so smart-punct-signature is no longer detector-only. Move it from section B to a partial mapping in section A, noting that the detector requires 4-signal co-occurrence while the skill rule treats curly quotes as a weak corroborating signal — the two agree in spirit but differ in mechanism. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: enforce CATEGORIES.md contract; docs: contributor guide + count clarity - detector/categories.test.js: asserts every detector type is documented in CATEGORIES.md and no stale type rows remain; wired into `npm test`. - README + CATEGORIES.md: note that the 42 prose patterns, 43 detector types, and ~50 SKILL.md sections are different counts on purpose — don't reconcile. - CONTRIBUTING.md + PR template: encode the regex-vs-judgment decision, the precision-over-recall bias, npm test, the clean-prose bar, and changelog/ version conventions — the things the first community PR surfaced by hand. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: require contributors to cite sources for empirical claims Rules that assert how AI or humans write get fact-checked; some turn out wrong (e.g. the curly-quote premise). Add a "Cite your sources" section to CONTRIBUTING.md and a checklist item to the PR template. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: require detector types to appear in a CATEGORIES.md table, not just prose Tighten the anti-drift check so a type "documented" by a stray backtick mention in prose no longer satisfies the gate — it has to land in an actual mapping-table row, matching the test's own summary line. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |