diff --git a/src/components/settings/__tests__/token-revoke-labels.test.ts b/src/components/settings/__tests__/token-revoke-labels.test.ts
new file mode 100644
index 000000000..880765edc
--- /dev/null
+++ b/src/components/settings/__tests__/token-revoke-labels.test.ts
@@ -0,0 +1,52 @@
+/**
+ * The token revoke confirmation names the act.
+ *
+ * Both token lists (API tokens and MCP connections) labelled the dialog's
+ * confirm button with `settings.tokenRevoked` — "Revoked", the status word the
+ * admin overview shows for a token that is already gone — so the button that
+ * performs the revoke read as if it had happened. The phone layout's trigger
+ * carried the dialog title instead, question mark included.
+ *
+ * Read from the source because the dialog content only mounts while open, and
+ * an SSR render never sees it. What is pinned: every `AlertDialogAction` that
+ * calls `handleRevoke` is labelled with the action key, and no trigger or
+ * action on these two surfaces uses the status word.
+ */
+import { readFileSync } from "node:fs";
+import { join } from "node:path";
+
+import { describe, expect, it } from "vitest";
+
+const FILES = [
+ "src/components/settings/api-section.tsx",
+ "src/components/settings/mcp-section.tsx",
+];
+
+function read(rel: string): string {
+ return readFileSync(join(process.cwd(), rel), "utf8");
+}
+
+/** The body of every `…` block. */
+function actions(source: string): string[] {
+ return [
+ ...source.matchAll(//g),
+ ].map((m) => m[0]);
+}
+
+describe("token revoke labels", () => {
+ for (const rel of FILES) {
+ it(`${rel}: the revoke confirm says "Revoke token"`, () => {
+ const revokes = actions(read(rel)).filter((a) =>
+ a.includes("handleRevoke(tok.id)"),
+ );
+ expect(revokes.length).toBeGreaterThan(0);
+ for (const action of revokes) {
+ expect(action).toContain('t("settings.tokenRevokeAction")');
+ }
+ });
+
+ it(`${rel}: never labels a control with the status word`, () => {
+ expect(read(rel)).not.toContain('t("settings.tokenRevoked")');
+ });
+ }
+});
diff --git a/src/components/settings/api-section.tsx b/src/components/settings/api-section.tsx
index fa0edc26b..267fd27d3 100644
--- a/src/components/settings/api-section.tsx
+++ b/src/components/settings/api-section.tsx
@@ -619,7 +619,7 @@ function ApiTokensCard() {
variant="destructive"
onClick={() => handleRevoke(tok.id)}
>
- {t("settings.tokenRevoked")}
+ {t("settings.tokenRevokeAction")}
@@ -698,7 +698,7 @@ function ApiTokensCard() {
className="min-h-11 w-full"
>
- {t("settings.tokenRevoke")}
+ {t("settings.tokenRevokeAction")}
@@ -718,7 +718,7 @@ function ApiTokensCard() {
variant="destructive"
onClick={() => handleRevoke(tok.id)}
>
- {t("settings.tokenRevoked")}
+ {t("settings.tokenRevokeAction")}
diff --git a/src/components/settings/mcp-section.tsx b/src/components/settings/mcp-section.tsx
index bc21fcb4f..6b448a5d6 100644
--- a/src/components/settings/mcp-section.tsx
+++ b/src/components/settings/mcp-section.tsx
@@ -516,7 +516,7 @@ function McpTokensCard() {
className="min-h-11 w-full"
>
- {t("settings.tokenRevoke")}
+ {t("settings.tokenRevokeAction")}
@@ -536,7 +536,7 @@ function McpTokensCard() {
variant="destructive"
onClick={() => handleRevoke(tok.id)}
>
- {t("settings.tokenRevoked")}
+ {t("settings.tokenRevokeAction")}