Designing Tests
CloudAI-X/claude-workflow-v2
Designs and implements testing strategies for any codebase. An agent skill from CloudAI-X/claude-workflow-v2.
Maintain test and documentation alignment — PHPUnit tests, async testing patterns, PHPDoc contracts, guide pages, and documentation workflow.
$ npx skills add discord-php/DiscordPHP --skill async-test-and-doc-sync -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install discord-php/DiscordPHP async-test-and-doc-sync --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/discord-php/DiscordPHP.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/async-test-and-doc-sync .claude/skills/async-test-and-doc-sync && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "async-test-and-doc-sync" agent skill from https://github.com/discord-php/DiscordPHP/tree/master/.agents/skills/async-test-and-doc-sync into .claude/skills/async-test-and-doc-sync/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "async-test-and-doc-sync", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/discord-php/DiscordPHP/tree/master/.agents/skills/async-test-and-doc-syncType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add discord-php/DiscordPHP --skill async-test-and-doc-sync -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install discord-php/DiscordPHP async-test-and-doc-sync --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/discord-php/DiscordPHP.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/async-test-and-doc-sync .agents/skills/async-test-and-doc-sync && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "async-test-and-doc-sync" agent skill from https://github.com/discord-php/DiscordPHP/tree/master/.agents/skills/async-test-and-doc-sync into .agents/skills/async-test-and-doc-sync/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "async-test-and-doc-sync", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add discord-php/DiscordPHP --skill async-test-and-doc-sync -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install discord-php/DiscordPHP async-test-and-doc-sync --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/discord-php/DiscordPHP.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/async-test-and-doc-sync .cursor/skills/async-test-and-doc-sync && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "async-test-and-doc-sync" agent skill from https://github.com/discord-php/DiscordPHP/tree/master/.agents/skills/async-test-and-doc-sync into .cursor/skills/async-test-and-doc-sync/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "async-test-and-doc-sync", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/discord-php/DiscordPHP.git --path .agents/skills/async-test-and-doc-sync--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add discord-php/DiscordPHP --skill async-test-and-doc-sync -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install discord-php/DiscordPHP async-test-and-doc-sync --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/discord-php/DiscordPHP.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/async-test-and-doc-sync .gemini/skills/async-test-and-doc-sync && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "async-test-and-doc-sync" agent skill from https://github.com/discord-php/DiscordPHP/tree/master/.agents/skills/async-test-and-doc-sync into .gemini/skills/async-test-and-doc-sync/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "async-test-and-doc-sync", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install discord-php/DiscordPHP async-test-and-doc-syncInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add discord-php/DiscordPHP --skill async-test-and-doc-sync -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/discord-php/DiscordPHP.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/async-test-and-doc-sync .github/skills/async-test-and-doc-sync && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "async-test-and-doc-sync" agent skill from https://github.com/discord-php/DiscordPHP/tree/master/.agents/skills/async-test-and-doc-sync into .github/skills/async-test-and-doc-sync/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "async-test-and-doc-sync", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add discord-php/DiscordPHP --skill async-test-and-doc-sync -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install discord-php/DiscordPHP async-test-and-doc-sync --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/discord-php/DiscordPHP.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/async-test-and-doc-sync .opencode/skills/async-test-and-doc-sync && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "async-test-and-doc-sync" agent skill from https://github.com/discord-php/DiscordPHP/tree/master/.agents/skills/async-test-and-doc-sync into .opencode/skills/async-test-and-doc-sync/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "async-test-and-doc-sync", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
async-test-and-doc-syncMaintain test and documentation alignment — PHPUnit tests, async testing patterns, PHPDoc contracts, guide pages, and documentation workflow.
Async Test And Doc Sync is an agent skill from discord-php/DiscordPHP. Maintain test and documentation alignment — PHPUnit tests, async testing patterns, PHPDoc contracts, guide pages, and documentation workflow. Use when adding tests, updating docs, or changing public behavior.
Its SKILL.md is about 3.4k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Testing & QA, covering Test strategy, Integration testing and Unit testing. It works with PHP and Discord. The repository describes itself as: An API to interact with the popular messaging app Discord. The licence is MIT.
10 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 580c66a. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
composeryarnFrom the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
discord.comFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
DISCORD_TOKENFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Async Test And Doc Sync loads about 3.4k tokens when it runs. Until then it costs about 58 tokens; SKILL.md has 1,558 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
3. `tests/bootstrap.php` — autoload, `.env` loading, singleton wiringST_CHANNEL`, and `TEST_CHANNEL_NAME` in `.env` or environment. `DiscordSingleton` shares a single connected client acrosIntegration tests require `.env` or shell variables: `DISCORD_TOKEN` (bot token), `TEST_CHANNEL` (channel ID), `TEST_CHAAutomated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from discord-php/DiscordPHP at commit 580c66a, republished under its MIT licence (© discord-php). 1,558 words, ~3,417 tokens.
.claude/skills/async-test-and-doc-sync/SKILL.md (or your agent's skills folder).Use this skill when adding or changing public behavior, updating builder validation or part semantics, writing or reviewing tests, updating PHPDoc blocks or guide pages, or touching anything user-facing enough that tests or docs should move with it.
This is alignment skill. Load it when the question is not "does the code work?" but "do tests prove it and do docs describe it?"
Keep tests, PHPDoc, and long-form documentation synchronized with the public behavior of parts, repositories, builders, and helpers:
tests/functions.php — wait() helper and getMockDiscord() factorytests/DiscordTestCase.php — integration base class with real channel setuptests/bootstrap.php — autoload, .env loading, singleton wiringphpunit.xml — test suite configuration, coverage settingstests/Builders/ModalBuilderTest.phptests/FunctionsTest.phptests/CollectionsTest.phptests/Parts/Channel/ChannelTest.phptests/Parts/Channel/Message/Embed/EmbedTest.phptests/Parts/Channel/Message/MessageTest.phpguide/ — long-form RST documentation for parts, events, buildersdocs/ — Gatsby site source for published documentationREADME.md — getting started, installation, basic usageCONTRIBUTING.md — contributor workflow and code style expectationsTests and docs in this repo are not afterthoughts. They form a contract surface:
@property and @property-read annotations on parts are how IDEs and users discover magic properties. If code adds a fillable field or getter mutator without updating the docblock, the property is effectively invisible to consumers.DiscordTestCase; use $this->getMockBuilder() for isolated class dependencies and getMockDiscord() when a lightweight real client is needed.DiscordTestCase prove that async flows work against real Discord infrastructure. These require environment variables and a live bot token.guide/ and Gatsby pages in docs/ describe recommended patterns. They should only change when public behavior or preferred usage actually changes — not for internal refactors.If a change touches public behavior but skips one of these surfaces, the contract is incomplete.
All unit-test classes must extend DiscordTestCase, including tests for logic isolated from Discord I/O:
contains(), studly(), escapeMarkdown(), poly_strlen())push(), map(), filter(), from())getMockDiscord()jsonSerialize() on buildersUse $this->getMockBuilder() for isolated class dependencies and getMockDiscord() when a lightweight real client is needed. DiscordTestCase supplies the shared test lifecycle and skips cleanly when Discord integration is unavailable.
Example: tests/Builders/ModalBuilderTest.php uses $this->expectException(\LogicException::class) and str_repeat('a', 101) to verify title length validation.
Use wait() and return the wait() call when the test must interact with real Discord infrastructure — sending/editing/deleting messages, pinning, creating invites, fetching message history, verifying embed hydration, or testing repository fetch()/freshen() against live API.
These tests require DISCORD_TOKEN, TEST_CHANNEL, and TEST_CHANNEL_NAME in .env or environment. DiscordSingleton shares a single connected client across the suite. Reach the live channel only through $this->channel(): it skips the test when there is no token, so the rest of the class still runs offline. A test that needs Discord some other way should check self::isLive() and skip itself.
A test that sends a request should not need Discord at all: set getMockHttpDriver() on a getMockDiscord() client and assert on the requests it records, as tests/Parts/Guild/GuildRequestsTest.php does. Those run in CI on every push and pull request (.github/workflows/tests.yml).
getMockDiscord() factoryDefined in tests/functions.php. Creates a minimal Discord instance with empty token and NullLogger — suitable for constructing parts and testing attribute access without connecting to gateway.
Use $this->getMockBuilder() for mocked class dependencies. Use getMockDiscord() for local client-backed tests; otherwise use and return wait() for asynchronous work.
Test files mirror the source structure. Builder tests live in tests/Builders/, part tests in tests/Parts/{Family}/, and utility tests in tests/ root. Infrastructure files (bootstrap.php, functions.php, DiscordSingleton.php, DiscordTestCase.php) live at the tests/ root.
tests/Builders/{BuilderName}Test.phptests/Parts/{Family}/{PartName}Test.phptests/ rootDiscordTestCaseDiscovers all *Test.php under tests/ recursively. Coverage tracks src/. Bootstrap is tests/bootstrap.php.
wait() bridgewait() in tests/functions.php bridges Promise-based async code into synchronous PHPUnit assertions:
function wait(callable $callback, float $timeout = TIMEOUT, ?callable $timeoutFn = null)It works by scheduling $callback on the ReactPHP loop via futureTick(), passing a $resolve callable that stops the loop and captures the result, adding a timeout timer (default 10s), running the loop synchronously, and re-throwing any captured exception after loop stops.
Promise chain with assertion then resolve:
return wait(function (Discord $discord, $resolve) {
$this->channel()->sendMessage('test content')
->then(fn (Message $m) => $this->assertEquals('test content', $m->content))
->then($resolve, $resolve);
});Custom timeout with fallback:
return wait(function (Discord $discord, $resolve) {
// ... async work ...
}, 10, fn () => $this->markTestIncomplete('Hit rate limit.'));Key rules:
$resolve as both fulfillment and rejection handler at the end of the chain$callback receives (Discord $discord, callable $resolve) — use $discord for client accesswait() call from the test method so PHPUnit tracks itTIMEOUT constant)Every part class should have class-level docblock annotations for @property (read/write magic properties from $fillable), @property-read (computed properties from mutators or repos), @method (delegated magic methods), @since (version introduced), and @link (Discord API docs URL).
PHPDoc in this repo serves three purposes: IDE autocompletion (consumers rely on @property since all access goes through __get()), generated reference (docs tooling reads annotations), and static analysis (Mago uses docblocks for type checking).
$fillable → add @property with type@property-read with return type$repositories → add @property-read for the repository typestring to ?string) → update annotation/**
* @property string $id
* @property string $name
* @property-read Carbon $created_at
* @property-read MemberRepository $members
* @link https://discord.com/developers/docs/resources/guild
*/
class Guild extends Partguide/ — long-form RST contentUser-facing guides organized by topic: basics.rst (getting started, intents), parts/ (per-resource docs), events/ (gateway handling), repositories.rst, message_builder.rst, components.rst, interactions.rst, permissions.rst, collection.rst, faq.rst.
docs/ — Gatsby sitePublished documentation website source. Build with cd docs && yarn install && yarn build.
README.mdInstallation, requirements, basic bot example. Update when minimum PHP version, major dependencies, or getting-started flow changes.
Docs should change when:
Docs should not change when:
| Purpose | Command |
|---|---|
| Run PHPUnit suite | composer unit |
| Static analysis | composer run-script mago-lint |
| Code style fixer | composer run-script cs |
| Non-mutating style check | ./vendor/bin/pint --test --config ./pint.json ./src |
| Compare with Discord's live OpenAPI description | composer openapi |
| Docs site build | cd docs && yarn install && yarn build |
Integration tests require .env or shell variables: DISCORD_TOKEN (bot token), TEST_CHANNEL (channel ID), TEST_CHANNEL_NAME (channel name). When absent, DiscordSingleton falls back to getMockDiscord(), the tests that use $this->channel() skip, and every other test runs.
Use --filter to target specific tests: ./vendor/bin/phpunit --filter ModalBuilderTest
jsonSerialize() output shape matches Discord API expectationsnew() factory wires arguments correctlyfromPart() round-trip preserves meaningful fieldsgetCreatableAttributes() / getUpdatableAttributes() include correct fieldssave() overridesStop if you see:
@property docblock entrywait() used in a test that never performs async I/OgetMockDiscord() used where asynchronous real client interaction is actually needed@property or @property-read in class docblockwait() pattern with proper $resolve chainingDiscordTestCasegetMockBuilder() or getMockDiscord() where appropriatewait() with proper $resolve chainingcomposer unit passescomposer run-script mago-lint reports no new issuesTests prove behavior, docblocks declare surface, guides teach usage — if any of these drift from the code, users and tooling lose trust in the library.
© discord-php, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .agents/skills/async-test-and-doc-sync of discord-php/DiscordPHP.
Open the folder on GitHubat commit 580c66a
Async Test And Doc Sync next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Async Test And Doc Sync this skilldiscord-php/DiscordPHP | 1.1k | — | ~3.4k | Automated safety check: Notes | MIT | |
| Designing TestsCloudAI-X/claude-workflow-v2 | 1.4k | 1 repos | ~1.5k | Automated safety check: Pass | MIT | |
| Robotics Testingarpitg1304/robotics-agent-skills | 368 | — | ~4.7k | Automated safety check: Pass | Apache-2.0 | |
| Akka.NET Testing PatternsAaronontheweb/dotnet-skills | 1.2k | 1 repos | ~2.4k | Automated safety check: Pass | MIT | |
| Rust Testingkurealnum/dotfiles | 290 | 6 repos | ~2.9k | Automated safety check: Pass | None | |
| MCP Testingadeze/raindrop-mcp | 188 | — | ~1.6k | Automated safety check: Pass | MIT |
CloudAI-X/claude-workflow-v2
Designs and implements testing strategies for any codebase. An agent skill from CloudAI-X/claude-workflow-v2.
arpitg1304/robotics-agent-skills
Testing strategies, patterns, and tools for robotics software.
Aaronontheweb/dotnet-skills
Shows how to test Akka.NET actors with Akka.Hosting.TestKit: swapping services for fakes, using TestProbes, and checking persistence, plus when the older TestKit still fits.
kurealnum/dotfiles
Rust testing patterns including unit tests, integration tests, async testing, property-based testing, mocking, and coverage.
adeze/raindrop-mcp
MCP Testing Strategies with Vitest, Inspector, and Integration Tests
novotnyllc/dotnet-artisan
Defines .NET test strategy and implementation patterns across xUnit v3 (Facts, Theories, fixtures, IAsyncLifetime), integration testing (WebApplicationFactory, Testcontainers), Aspire testing…
discord-php/DiscordPHP
Audit checklist for DiscordPHP bots and API libraries — stop the bot token leaking to third-party APIs or logs, keep secrets out of customids and exception messages, use constant-time comparison and…
discord-php/DiscordPHP
Scaffold and maintain a DiscordPHP-based bot or an API-library-on-DiscordPHP (the DiscordPHP-MTG / DiscordPHP-NHA / DiscordPHP-Sabacc pattern) — client subclass, third-party HTTP layer, Parts…
discord-php/DiscordPHP
Build DiscordPHP slash commands and message components — global command trees with subcommands, user- AND guild-installable commands usable in DMs / group DMs / guild channels, Components V2…
discord-php/DiscordPHP
Work with DiscordPHP's infrastructure utilities — CacheWrapper, CacheConfig, BigInt, Multipart, Endpoint::bind URL templates, Collection base class, and domain Exceptions.
discord-php/DiscordPHP
Maintain Part domain models — fillable attributes, mutators, typed nested data, save/fetch behavior, permission checks, PHPDoc, and repository bindings.
discord-php/DiscordPHP
Maintain Discord.php runtime bootstrapping, startup options, event loop, gateway connection, reconnection, member chunking, cache configuration, and process lifecycle.
Categories
Maintain test and documentation alignment — PHPUnit tests, async testing patterns, PHPDoc contracts, guide pages, and documentation workflow. Async Test And Doc Sync is an agent skill from discord-php/DiscordPHP. Maintain test and documentation alignment — PHPUnit tests, async testing patterns, PHPDoc contracts, guide pages, and documentation workflow.
Async Test And Doc Sync fits situations like: changing public behavior; tasks that involve Test strategy; tasks that involve Integration testing.
Run `npx skills add discord-php/DiscordPHP --skill async-test-and-doc-sync -a claude-code`. Or copy the skill folder (.agents/skills/async-test-and-doc-sync in discord-php/DiscordPHP) into .claude/skills/async-test-and-doc-sync in your project. Claude Code loads it when a task matches its description.
Run `npx skills add discord-php/DiscordPHP --skill async-test-and-doc-sync -a codex`. Or copy the skill folder (.agents/skills/async-test-and-doc-sync in discord-php/DiscordPHP) into .agents/skills/async-test-and-doc-sync in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add discord-php/DiscordPHP --skill async-test-and-doc-sync -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/async-test-and-doc-sync, .gemini/skills/async-test-and-doc-sync, .github/skills/async-test-and-doc-sync and .opencode/skills/async-test-and-doc-sync in your project.
Going by SKILL.md and its folder, Async Test And Doc Sync needs the command-line tools its instructions call (composer and yarn) and credentials named DISCORD_TOKEN. Our summary lists: A credential in DISCORD_TOKEN.
SKILL.md names 1 domain. In commands or code: discord.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.
Async Test And Doc Sync is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.4k tokens (SKILL.md is roughly 14k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Async Test And Doc Sync: Designing Tests (CloudAI-X/claude-workflow-v2, 1.4k stars), Robotics Testing (arpitg1304/robotics-agent-skills, 368 stars), Akka.NET Testing Patterns (Aaronontheweb/dotnet-skills, 1.2k stars) and Rust Testing (kurealnum/dotfiles, 290 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
discord-php (a GitHub organization) maintains it in discord-php/DiscordPHP, which has 1,080 GitHub stars. The repository holds 14 skills in this directory. The repository was last updated on October 6, 2026.
Source: discord-php/DiscordPHP on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.