Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
- You are a Founding Engineer on this team; any decisions you make will come back to haunt you, so you'd better be sure to consider the consequences of your decisions and minimize the pain you create.
- Retain worklogs in `/notes`, documenting decisions made. No fluff; low noise/high signal. You're a staff engineer writing for your peers.
- Note filenames MUST follow the format `<date>_<X>_<title>.md`, i.e. a date prefix in the format YYYY-MM-DD; a sequence where x is a monotonically increasing integer, and a title for the document.
- Commit periodically.
- This project uses sqlite, so you can inspect the database yourself. You can make your own dummy data, but don't do anything destructive.
- You are a Founding Engineer on this team; any decisions you make will come back
to haunt you, so you'd better be sure to consider the consequences of your
decisions and minimize the pain you create.
- Write your thoughts in `/notes`, especially if it will help you remember
important implementation details later.
- Your notes must be named consistently with a date prefix in the format
`YYYY-MM-DD_X_title.md` where X is a monotonically increasing integer.
- This project uses sqlite at `./mod-bot.sqlite3`, so you can inspect the database
yourself.
- Prefer using your Playwright MCP over curl.
- If touching Effect-TS code, consult @notes/EFFECT.md.

When starting a new project, always read the README.md file in the root
directory.
2 changes: 1 addition & 1 deletion app/commands/escalate/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {

import { client } from "#~/discord/client.server.ts";
import { executeResolution } from "#~/discord/escalationResolver.js";
import { deleteAllReportedForUser } from "#~/effects/models/reportedMessages.js";
import { hasModRole } from "#~/helpers/discord.js";
import { parseFlags } from "#~/helpers/escalationVotes.js";
import type { Features } from "#~/helpers/featuresFlags.js";
Expand Down Expand Up @@ -38,7 +39,6 @@ import {
fetchSettings,
SETTINGS,
} from "#~/models/guilds.server";
import { deleteAllReportedForUser } from "#~/models/reportedMessages.server";

import {
buildConfirmedMessageContent,
Expand Down
2 changes: 1 addition & 1 deletion app/commands/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import {
type MessageContextMenuCommandInteraction,
} from "discord.js";

import { ReportReasons } from "#~/effects/models/reportedMessages.js";
import { commandStats } from "#~/helpers/metrics";
import { reportUser } from "#~/helpers/modLog";
import { log, trackPerformance } from "#~/helpers/observability";
import { ReportReasons } from "#~/models/reportedMessages.server";

const command = new ContextMenuCommandBuilder()
.setName("Report")
Expand Down
6 changes: 3 additions & 3 deletions app/commands/track.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import {
import { Button } from "reacord";

import { reacord } from "#~/discord/client.server";
import { reportUser } from "#~/helpers/modLog";
import {
markMessageAsDeleted,
markMessageAsDeletedLegacy as markMessageAsDeleted,
ReportReasons,
} from "#~/models/reportedMessages.server";
} from "#~/effects/models/reportedMessages.js";
import { reportUser } from "#~/helpers/modLog";

const command = new ContextMenuCommandBuilder()
.setName("Track")
Expand Down
8 changes: 4 additions & 4 deletions app/discord/automod.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Events, type Client } from "discord.js";

import {
markMessageAsDeletedLegacy as markMessageAsDeleted,
ReportReasons,
} from "#~/effects/models/reportedMessages.js";
import { isStaff } from "#~/helpers/discord";
import { isSpam } from "#~/helpers/isSpam";
import { reportUser } from "#~/helpers/modLog";
import {
markMessageAsDeleted,
ReportReasons,
} from "#~/models/reportedMessages.server";

import { client } from "./client.server";

Expand Down
2 changes: 1 addition & 1 deletion app/discord/honeypotTracker.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ChannelType, Events, type Client } from "discord.js";

import db from "#~/db.server.js";
import { ReportReasons } from "#~/effects/models/reportedMessages.js";
import { reportUser } from "#~/helpers/modLog.js";
import { log } from "#~/helpers/observability";
import { fetchSettings, SETTINGS } from "#~/models/guilds.server.js";
import { ReportReasons } from "#~/models/reportedMessages.server.js";

interface HoneypotConfig {
guild_id: string;
Expand Down
42 changes: 42 additions & 0 deletions app/effects/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Data } from "effect";

// Tagged error types for discriminated unions
// Each error has a _tag property for pattern matching with Effect.catchTag

export class DiscordApiError extends Data.TaggedError("DiscordApiError")<{
operation: string;
discordError: unknown;
}> {}

export class DatabaseError extends Data.TaggedError("DatabaseError")<{
operation: string;
cause: unknown;
}> {}

export class DatabaseConstraintError extends Data.TaggedError(
"DatabaseConstraintError",
)<{
operation: string;
constraint: string;
cause: unknown;
}> {}

export class StripeApiError extends Data.TaggedError("StripeApiError")<{
operation: string;
stripeError: unknown;
}> {}

export class NotFoundError extends Data.TaggedError("NotFoundError")<{
resource: string;
id: string;
}> {}

export class ValidationError extends Data.TaggedError("ValidationError")<{
field: string;
message: string;
}> {}

export class ConfigError extends Data.TaggedError("ConfigError")<{
key: string;
message: string;
}> {}
Loading