Skip to content

docs(4.1): match the theming, cooldowns, testing, services and troubleshooting pages to 4.1.0 - #233

Merged
l7aromeo merged 3 commits into
mainfrom
docs/verify-4.1.0-d
Oct 3, 2026
Merged

l7aromeo merged 3 commits into
mainfrom
docs/verify-4.1.0-d

Conversation

@l7aromeo

@l7aromeo l7aromeo commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Every claim on fifteen 4.1 pages checked against meocord 4.1.0 (main at b6113d30), and the examples at 4.1.0-beta.12. Thirteen pages change; sharding and database are unchanged, having no claim that needed it.

Three statements here describe behaviour from two meocord fixes, meocord/meocord#418 and meocord/meocord#419, both merged:

  • invoke refuses a command another handler takes by its subcommand path (invoke-and-dispatch);
  • a guard, interceptor, filter, pipe or presenter that injects Translator without @MeoCord({ i18n }) stops the bot at startup (localisation);
  • the testing module names each class that injects the Client it doesn't make, a guard, interceptor or filter included (testing).

Pages

Page Changes
cooldowns @Cooldown on autocomplete, reaction and event handlers is refused, and a controller's skips them; the early check runs when a message command must fetch; a stranger's press is counted under the stranger's id; a refused message command is told by DM with dmOnCooldown
cooldown-stores bypassed cooldowns are left out of consumeMany; a dmOnCooldown notice is counted under :notice:
theming @UseTheme inherits as far as inheritStages lets it; the app theme is given up when the start fails; a failed lookup isn't asked again for 10 seconds; the theme testing helpers live in Testing recipes
localisation lowercase names are a slash command rule; Translator in a guard, interceptor or filter
i18n-bot a plain-variable catalog's params are checked by expectCompleteCatalog, the keys at compile time
testing app passes the whole message options; Client in a stage class
testing-recipes the module's store is the app's when it sets one; a UserError after a message is a reply in its channel
mocks getChannel with channelTypes and getFocused throw; which methods a deleted message refuses; options in the overrides
invoke-and-dispatch a message passed alone gets its pattern's params; command routing; emit's AggregateError holds the errors
services an abstract class needs no @Inject; shared classes can't inject ExecutionContext; the import-cycle rule needs the TypeScript resolver; a gotcha for the undecorated-class refusal
troubleshooting entries for the undecorated-class refusal, decorators on the wrong target, and the class-decorator-on-a-method warning; the ExecutionContext messages of shared classes; the app class's name in App:; intents for DM and mention-only message commands
lifecycle-hooks the themeFor class and shared guards, interceptors and filters get hooks; its place in the order
security the Logger prints the token as [redacted]

Two claims kept, with their sources

  • Redis 5 and later (cooldown-stores). The store's scripts call TIME before they write, without redis.replicate_commands(). Redis's own documentation, Scripting with Lua: "In Redis 5.0, effects replication became the default mode", and with it "the restrictions on non-deterministic functions are removed. You can, for example, use the TIME … commands inside your scripts freely". The other commands the store sends (ZADD, ZRANGE … WITHSCORES, ZREMRANGEBYSCORE, ZCOUNT, ZCARD, ZREM, PEXPIRE, EVAL and EVALSHA) date from Redis 2.
  • node:sqlite without a flag from Node 22.13 (cooldown-stores). Node's v22.13.0 changelog, semver-minor commits: "doc,lib,src,test: unflag sqlite module" (nodejs/node#55890).

Checks

bun run content:check, bun run examples:check (4.1 against meocord 4.1.0-beta.12, its specs included), prettier and eslint pass.

@l7aromeo l7aromeo left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked every changed claim at 263fc9c against meocord b6113d30. Quoted messages match the source, and every removed line was wrong or incomplete. Three claims wait on the two meocord fixes this PR names, so I left them unjudged: invoke's subcommand-path refusal, Translator in a stage class, and Client in a stage class.

Lines to fix:

  1. cooldowns.md, early check. "must fetch a member, user, role or channel": a role is never fetched. It is in the cache at parse or the call is invalid (message-params.ts, "Roles are cached with the Guilds intent"), and MessageEntityRef.resolve() returns the cached role without a request (message-entities.ts, this.kind === 'role'). Suggested: "must fetch a member, user or channel its params name, or a value of one of the app's own types".
  2. cooldowns.md, dmOnCooldown. "the author gets the same wait by DM, in meocord.dm.cooldown" holds for a command sent in a server. For one sent in a DM, fallback.ts answers there with the plain cooldown text (if (!message.guild) return presentedReply(… errorText(…)), which gives meocord.cooldown.until). Suggested: "the author of a command sent in a server gets the same wait by DM, in meocord.dm.cooldown, which names the command, channel and server; a command sent in a DM is answered there with meocord.cooldown.until."
  3. services.md, heading. "A class without @Service() can't be injected if its constructor takes parameters" is broader than the check. undecoratedConstructor fires only when the parameters have no recorded types and no @Inject token, and TypeScript records design:paramtypes for a class whose constructor parameter carries a decorator. Suggested: "A class without a decorator can't be injected if its constructor takes parameters. With no decorator on the class or on a parameter, TypeScript records none of their types, so the bot stops, naming the class:"
  4. services.md and troubleshooting.md, "Logger and MeoCord's errors aren't injected". The advice map (meocord-classes.ts) covers Logger, CooldownError, CooldownStoreError, GuardDeniedError, MessageUsageError, UserError and ValidationError, but not CommandNotFoundError. Its constructor has a default message, so its length is 0 and it passes the check. Suggested: "Logger and errors such as UserError".
  5. troubleshooting.md, refusal prefixes. "App: for @MeoCord's options, the app class's name, …" reads as two prefixes. The prefix is always ${target.name}: (app.decorator.ts, meocord-factory.ts). Suggested: "the app class's name, such as App:, for @MeoCord's options, meocord.config.ts: for its settings, …"

Optional:

  • lifecycle-hooks.md: the "unless" list for stage classes leaves out a guard listed in providers, and one injected by an observer, the themeFor class or the store. "Unless the app also binds it: listed in services or providers, or injected by a class that gets hooks" covers them.
  • invoke-and-dispatch.md: a message passed alone matches after the app's prefix, the handler's own prefix, or a mention.
  • testing-recipes.md: a test's own CooldownStore provider can be one instance shared between modules.

Out of the docs, now being fixed in meocord: registration checks a context menu's localised names against 100 characters (command-localizations.ts, chatInputName ? 32 : 100), where Discord allows 32. The localisation.md sentence is right once that lands.

content:check and examples:check pass on the head.

@l7aromeo l7aromeo left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rechecked 202d7f9. The five fixes and three optional notes all match meocord b6113d30:

  • the role-free early check;
  • the DM notice scoped to commands sent in a server;
  • the undecorated-class heading;
  • "errors such as UserError";
  • the app-name prefix;
  • the hooks "unless the app also binds it" list;
  • the handler's own prefix or a mention;
  • the test's own CooldownStore provider.
    No blockers left beyond the three claims waiting on #418 and #419.

…eshooting pages to 4.1.0

Checked every claim on these pages against the 4.1.0 code:
- cooldowns: which handlers @cooldown applies to, when a message command
  is checked early, why a stranger's press leaves the owner's count alone,
  and how a refused message command is told;
- cooldown stores: bypassed cooldowns and dmOnCooldown notices;
- theming: the inheritStages limit, the app theme after a failed start,
  the 10 s failure backoff, and the testing links;
- localisation and i18n-bot: name rules, Translator in stages, and
  which catalogs are compile-checked;
- testing, testing recipes, mocks, invoke and dispatch: the app's store,
  message options, Client in stages, UserError answers, option getters,
  deleted messages, options in overrides, message params, command
  routing and emit's AggregateError;
- services and troubleshooting: the undecorated-class refusal,
  decorators on the wrong target, ExecutionContext in shared classes, and
  message command intents;
- lifecycle hooks: shared guards and the themeFor class;
- security: the Logger redacts the token.
…ted-class rule

The early check fetches no role; a cooldown DM goes only to commands sent in
a server; a parameter decorator also records types; errors without
parameters aren't in the 'not injected' advice; the app class's name is the
prefix for @meocord's options. Lifecycle hooks name providers, invoke names
the handler prefix and mentions, and testing recipes says how a provided
store is shared.
Translator is refused for pipes and the presenter too, naming the class; a
testing module's missing Client names every class of the module that
injects it.
@l7aromeo
l7aromeo force-pushed the docs/verify-4.1.0-d branch from 202d7f9 to d61ef49 Compare October 3, 2026 06:17
@l7aromeo
l7aromeo marked this pull request as ready for review October 3, 2026 06:17

@l7aromeo l7aromeo left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rechecked d61ef49 against meocord 08757577, which is on main.

  • localisation.md: assertStartupClasses refuses with missingTranslatorError(cls) ("Class: it injects Translator, but @meocord has no i18n. Pass @meocord({ i18n: t }), …") for every startup class. startup-roots.spec's PLACES include a pipe and the presenter.
  • testing.md: compile() binds Client to a toDynamicValue that throws "A, B inject the Discord Client, which a testing module does not make: …" for every class that injects it, so it is refused where it is resolved.
    Both lines match. No blockers.

@l7aromeo
l7aromeo added this pull request to the merge queue Oct 3, 2026
Merged via the queue into main with commit ffde02c Oct 3, 2026
8 checks passed
@l7aromeo
l7aromeo deleted the docs/verify-4.1.0-d branch October 3, 2026 06:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant