diff --git a/apps/decodex-app/Sources/DecodexApp/AccountPanelView.swift b/apps/decodex-app/Sources/DecodexApp/AccountPanelView.swift
index 2716401a1..825c746ff 100644
--- a/apps/decodex-app/Sources/DecodexApp/AccountPanelView.swift
+++ b/apps/decodex-app/Sources/DecodexApp/AccountPanelView.swift
@@ -480,7 +480,8 @@ struct AccountPanelView: View {
if let selector = control.accountSelector, !selector.isEmpty {
if emailsHidden {
- let value = account(matching: selector)?.panelDisplayName(emailsHidden: true) ?? "Account"
+ let value = account(matching: selector)?.panelDisplayName(emailsHidden: true)
+ ?? AccountDisplay.alias(forIdentity: selector)
return "To \(value)"
}
@@ -1116,7 +1117,6 @@ private enum AccountPrivacy {
private enum AccountDisplay {
static let randomNames = [
- "Alex",
"Avery",
"Bailey",
"Blake",
diff --git a/apps/decodex/src/accounts.rs b/apps/decodex/src/accounts.rs
index a516f940f..50524b435 100644
--- a/apps/decodex/src/accounts.rs
+++ b/apps/decodex/src/accounts.rs
@@ -21,11 +21,11 @@ use crate::{
};
const ACCOUNT_RANDOM_NAMES: &[&str] = &[
- "Alex", "Avery", "Bailey", "Blake", "Casey", "Charlie", "Clara", "Dana", "Drew", "Eden",
- "Elliot", "Emery", "Evan", "Finley", "Harper", "Hayden", "Iris", "Jamie", "Jordan", "Kai",
- "Kendall", "Lane", "Liam", "Logan", "Mason", "Maya", "Mia", "Morgan", "Noah", "Nora", "Owen",
- "Paige", "Parker", "Quinn", "Reese", "Remy", "Riley", "Rowan", "Sage", "Sasha", "Sidney",
- "Taylor", "Theo", "Val",
+ "Avery", "Bailey", "Blake", "Casey", "Charlie", "Clara", "Dana", "Drew", "Eden", "Elliot",
+ "Emery", "Evan", "Finley", "Harper", "Hayden", "Iris", "Jamie", "Jordan", "Kai", "Kendall",
+ "Lane", "Liam", "Logan", "Mason", "Maya", "Mia", "Morgan", "Noah", "Nora", "Owen", "Paige",
+ "Parker", "Quinn", "Reese", "Remy", "Riley", "Rowan", "Sage", "Sasha", "Sidney", "Taylor",
+ "Theo", "Val",
];
pub(crate) struct AccountLoginRequest {
diff --git a/apps/decodex/src/orchestrator/operator_dashboard.html b/apps/decodex/src/orchestrator/operator_dashboard.html
index cd430e217..d75cc6239 100644
--- a/apps/decodex/src/orchestrator/operator_dashboard.html
+++ b/apps/decodex/src/orchestrator/operator_dashboard.html
@@ -3441,7 +3441,6 @@
Run History
const ACCOUNT_IDENTITY_EDGE_CHARS = 6;
const ACCOUNT_IDENTITY_MIN_EDGE_CHARS = 3;
const ACCOUNT_RANDOM_NAMES = [
- "Alex",
"Avery",
"Bailey",
"Blake",
@@ -4480,6 +4479,12 @@ Run History
: [];
}
+ function configuredDashboardAccounts(snapshot) {
+ return Array.isArray(snapshot?.accounts)
+ ? [...accountApiAccounts(), ...snapshot.accounts.filter(Boolean)]
+ : accountApiAccounts();
+ }
+
function noteAccountApiSnapshot(response) {
if (!response || !Array.isArray(response.accounts)) {
return false;
@@ -5753,9 +5758,7 @@ Run History
return null;
}
- const accounts = Array.isArray(snapshot.accounts)
- ? snapshot.accounts.filter(Boolean)
- : [];
+ const accounts = configuredDashboardAccounts(snapshot);
if (!accounts.length) {
return null;
}
@@ -5842,6 +5845,52 @@ Run History
);
}
+ function configuredCodexAccountFor(account, snapshot) {
+ const identity = codexAccountIdentity(account);
+ const email = codexAccountEmail(account);
+ const fingerprint = codexAccountFingerprint(account);
+ if (!identity && !email && !fingerprint) {
+ return null;
+ }
+
+ return (
+ configuredDashboardAccounts(snapshot).find(
+ (candidate) =>
+ (identity && codexAccountIdentity(candidate) === identity) ||
+ (email && codexAccountEmail(candidate) === email) ||
+ (fingerprint && codexAccountFingerprint(candidate) === fingerprint),
+ ) || null
+ );
+ }
+
+ function codexAccountDisplaySource(account, snapshot) {
+ const configured = configuredCodexAccountFor(account, snapshot);
+ if (!configured) {
+ return account;
+ }
+
+ const merged = { ...configured, ...account };
+ if (!String(merged.random_name || "").trim()) {
+ merged.random_name = configured.random_name;
+ }
+ if (!String(merged.random_name_key || "").trim()) {
+ merged.random_name_key = configured.random_name_key;
+ }
+ const accountOffset = account?.random_name_offset;
+ const accountHasOffset =
+ accountOffset != null &&
+ !(typeof accountOffset === "string" && !accountOffset.trim()) &&
+ Number.isInteger(Number(accountOffset));
+ if (
+ !accountHasOffset &&
+ Number.isInteger(Number(configured.random_name_offset))
+ ) {
+ merged.random_name_offset = configured.random_name_offset;
+ }
+
+ return merged;
+ }
+
function accountSelectionConfirmationKey(action, selector) {
return `${String(action || "").trim()}:${String(selector || "").trim()}`;
}
@@ -6138,6 +6187,17 @@ Run History
: codexAccountDisplayName(account);
}
+ function codexAccountFallbackName(value) {
+ const selector = String(value || "").trim();
+ if (!selector) {
+ return "account";
+ }
+
+ return accountEmailsHidden
+ ? codexAccountRandomName({ account_fingerprint: selector })
+ : compactAccountIdentity(selector);
+ }
+
function codexAccountPlanLabel(account) {
return account?.plan_type ? humanizeToken(account.plan_type) : "-";
}
@@ -6638,7 +6698,7 @@ Run History
return `Fixed · ${label}`;
}
- return `Fixed · ${accountEmailsHidden ? "account" : compactAccountIdentity(selector)}`;
+ return `Fixed · ${codexAccountFallbackName(selector)}`;
}
function renderAccountModeControl(snapshot) {
@@ -6678,9 +6738,10 @@ Run History
`;
}
- const displayTitle = codexAccountDisplayTitle(account);
- const visibleName = codexAccountVisibleName(account);
- const identityClass = codexAccountShowsEmail(account) ? " is-machine" : "";
+ const displayAccount = codexAccountDisplaySource(account, snapshot);
+ const displayTitle = codexAccountDisplayTitle(displayAccount);
+ const visibleName = codexAccountVisibleName(displayAccount);
+ const identityClass = codexAccountShowsEmail(displayAccount) ? " is-machine" : "";
const pendingTitle = capturedAccount
? displayTitle
: `${displayTitle || visibleName} · run account capture pending`;
@@ -6718,9 +6779,7 @@ Run History
function codexAccountPoolAccounts(snapshot) {
const accountsByIdentity = new Map();
- const configuredAccounts = Array.isArray(snapshot?.accounts)
- ? [...accountApiAccounts(), ...snapshot.accounts.filter(Boolean)]
- : accountApiAccounts();
+ const configuredAccounts = configuredDashboardAccounts(snapshot);
const runs = [
...(snapshot?.active_runs ?? []).map((run) => [run, true]),
...(snapshot?.recent_runs ?? []).map((run) => [run, false]),
@@ -7468,7 +7527,17 @@ Run History
function runIssueTitle(run, derived) {
const issueRecord = runIssueRecord(run, derived);
- return run.title || run.issue_title || issueRecord?.title || humanizeToken(run.current_operation || run.phase);
+ const operationFallback = humanizeToken(run.current_operation || run.phase);
+ const fallback = issueDisplayKey(run);
+
+ for (const value of [run.title, run.issue_title, issueRecord?.title]) {
+ const title = String(value || "").trim();
+ if (title && !(fallback !== "unknown" && title === operationFallback)) {
+ return title;
+ }
+ }
+
+ return fallback !== "unknown" ? fallback : operationFallback;
}
function runHealthText(run) {
@@ -9312,10 +9381,25 @@ ${escapeHtml(worktree.branch_name)}
merged[key] = snapshotRun[key];
}
}
+ if (
+ dashboardRunTitleIsOperationFallback(activityRun) &&
+ dashboardRunFieldHasValue(snapshotRun.title)
+ ) {
+ merged.title = snapshotRun.title;
+ }
return merged;
}
+ function dashboardRunTitleIsOperationFallback(run) {
+ const title = String(run?.title || "").trim();
+ if (!title || issueDisplayKey(run) === "unknown") {
+ return false;
+ }
+
+ return title === humanizeToken(run?.current_operation || run?.phase);
+ }
+
function dashboardRunIdentityKeys(run) {
const keys = run?.run_id ? [`run:${run.run_id}`] : [];
diff --git a/apps/decodex/src/orchestrator/tests/operator/status/dashboard.rs b/apps/decodex/src/orchestrator/tests/operator/status/dashboard.rs
index eb4f439c7..a27746754 100644
--- a/apps/decodex/src/orchestrator/tests/operator/status/dashboard.rs
+++ b/apps/decodex/src/orchestrator/tests/operator/status/dashboard.rs
@@ -532,9 +532,11 @@ fn operator_dashboard_account_privacy_controls_use_compact_identities() {
assert!(response.contains("function loadAccountNameOffsets()"));
assert!(response.contains("function persistAccountPrivacy(hidden)"));
assert!(response.contains("function persistAccountNameOffsets()"));
+ assert!(response.contains("function configuredDashboardAccounts(snapshot)"));
assert!(response.contains("function renderAccountPrivacyToggle()"));
assert!(response.contains("function codexAccountRandomNameKey(account)"));
assert!(response.contains("function codexAccountRandomNameOffset(account)"));
+ assert!(response.contains("function codexAccountDisplaySource(account, snapshot)"));
assert!(response.contains("function renderCodexAccountRandomNameButton(account)"));
assert!(response.contains("function codexAccountShowsEmail(account)"));
assert!(response.contains("function codexAccountPrivacyLabel(account)"));
@@ -551,12 +553,14 @@ fn operator_dashboard_account_privacy_controls_use_compact_identities() {
assert!(response.contains(": codexAccountVisibleName(account);"));
assert!(response.contains("return \"Balanced\";"));
assert!(response.contains("return `Fixed · ${label}`;"));
- assert!(response.contains("return `Fixed · ${accountEmailsHidden ? \"account\" : compactAccountIdentity(selector)}`;"));
+ assert!(response.contains("function codexAccountFallbackName(value)"));
+ assert!(response.contains("return `Fixed · ${codexAccountFallbackName(selector)}`;"));
assert!(response.contains("const title = codexAccountControlStatusLabel(snapshot);"));
assert!(!response.contains("const title = `Mode ${modeLabel}`;"));
assert!(response.contains("account-name-reroll"));
assert!(response.contains("data-account-name-reroll"));
assert!(response.contains("aria-label=\"Change account name\""));
+ assert!(!response.contains("\"Alex\""));
assert!(response.contains("return `${local.slice(0, 3)}...${local.slice(-3)}${domain}`;"));
assert!(response.contains("return ACCOUNT_RANDOM_NAMES[index];"));
assert!(response.contains("return status === \"selected\" ? 1 : 0;"));
@@ -1513,6 +1517,10 @@ fn operator_dashboard_run_activity_preserves_snapshot_detail_fields() {
assert!(response.contains("function mergeDashboardRunRecord(snapshotRun, activityRun)"));
assert!(response.contains("function mergeDashboardActiveRuns(snapshot, activeRunRows)"));
+ assert!(response.contains("function dashboardRunTitleIsOperationFallback(run)"));
+ assert!(response.contains("const operationFallback = humanizeToken(run.current_operation || run.phase);"));
+ assert!(response.contains("!(fallback !== \"unknown\" && title === operationFallback)"));
+ assert!(response.contains("return fallback !== \"unknown\" ? fallback : operationFallback;"));
assert!(response.contains("let dashboardLiveActiveRuns = [];"));
assert!(response.contains("let dashboardLiveAccounts = null;"));
assert!(response.contains("let dashboardLiveAccountControl = null;"));
@@ -1528,6 +1536,8 @@ fn operator_dashboard_run_activity_preserves_snapshot_detail_fields() {
assert!(response.contains("\"protocol_activity\""));
assert!(response.contains("!dashboardRunFieldHasValue(activityRun[key])"));
assert!(response.contains("merged[key] = snapshotRun[key];"));
+ assert!(response.contains("dashboardRunTitleIsOperationFallback(activityRun)"));
+ assert!(response.contains("merged.title = snapshotRun.title;"));
assert!(
response.contains("const mergedActiveRuns = mergeDashboardActiveRuns(snapshot, activeRunRows);")
);
diff --git a/apps/decodex/src/orchestrator/tests/operator/status/http.rs b/apps/decodex/src/orchestrator/tests/operator/status/http.rs
index ea649a09b..cd5396265 100644
--- a/apps/decodex/src/orchestrator/tests/operator/status/http.rs
+++ b/apps/decodex/src/orchestrator/tests/operator/status/http.rs
@@ -1413,7 +1413,7 @@ fn operator_state_endpoint_persists_account_random_name_offset() {
assert_eq!(data["accounts"][0]["random_name_offset"], 1);
assert_eq!(data["accounts"][0]["random_name_key"], "df65f796");
- assert_eq!(data["accounts"][0]["random_name"], "Logan");
+ assert_eq!(data["accounts"][0]["random_name"], "Taylor");
assert!(
fs::read_to_string(accounts_dir.join("config.toml"))
.expect("global config should read")