Skip to content

Commit 55663d7

Browse files
committed
fix(service-messaging): the boot conversion reports the engine's own error text, not the raw-SQL seam helper's
types' test:repo enumerates every operatorFacingErrorText caller with a sentinel pin against raw statements; the conversion became an unlisted caller. It never touches the raw seam: its reads and writes go through the data engine, whose errors carry no composed seam fault and whose SQL driver already redacts statements, so the package's plain message reading is the right one. Claude-Session: https://claude.ai/code/session_01UnHcTADjeg3VwxF21QHj7W Co-authored-by: Claude <noreply@anthropic.com>
1 parent cd4c2cb commit 55663d7

1 file changed

Lines changed: 19 additions & 3 deletions

File tree

‎packages/services/service-messaging/src/preference-user-conversion.ts‎

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
*/
4444

4545
import type { IDataEngine } from '@objectstack/spec/contracts';
46-
import { isMissingTableError, isUniqueViolationError, operatorFacingErrorText } from '@objectstack/types';
46+
import { isMissingTableError, isUniqueViolationError } from '@objectstack/types';
4747
import { PREFERENCE_OBJECT } from './preference-resolver.js';
4848

4949
/** The sentinel the text column held for the admin-global default. Read here and nowhere else. */
@@ -93,6 +93,22 @@ export interface PreferenceUserConversionResult {
9393
detail?: string;
9494
}
9595

96+
/**
97+
* The text an engine refusal reports, for the boot log and the result.
98+
*
99+
* Every read and write here goes through the data ENGINE, never the raw-SQL
100+
* seam, so the error in hand is the engine's own (a validation finding, a
101+
* `DUPLICATE_RECORD`, a driver error the SQL driver already redacts of its
102+
* statement and bound values). That is why this is the package's plain
103+
* `message` reading and not `operatorFacingErrorText`, the helper that digs a
104+
* dialect's words out of the raw seam's composed fault: there is no such fault
105+
* on this path, and each of that helper's callers is enumerated and pinned
106+
* against raw statements this module never issues.
107+
*/
108+
function messageOf(err: unknown): string {
109+
return err instanceof Error ? err.message : String(err);
110+
}
111+
96112
function textOrNull(value: unknown): string | null {
97113
return value === null || value === undefined ? null : String(value);
98114
}
@@ -136,7 +152,7 @@ export async function convertWildcardPreferenceUsers(
136152
// No table yet holds no '*' row — a fresh database, or a boot whose
137153
// schema sync is skipped. Anything else is "could not look".
138154
if (isMissingTableError(err, object)) return { status: 'absent', converted, missed };
139-
const detail = operatorFacingErrorText(err);
155+
const detail = messageOf(err);
140156
logger?.error(
141157
`[messaging] could not read ${object} to rewrite user_id '${LEGACY_WILDCARD_USER}' to the empty ` +
142158
'reference, so any admin-global notification default still stored that way is NOT applying: ' +
@@ -174,7 +190,7 @@ export async function convertWildcardPreferenceUsers(
174190
topic: textOrNull(row.topic),
175191
channel: textOrNull(row.channel),
176192
reason: duplicate ? 'duplicate' : 'failed',
177-
detail: operatorFacingErrorText(err),
193+
detail: messageOf(err),
178194
});
179195
}
180196
}

0 commit comments

Comments
 (0)