Skip to content

Commit 2c0a97b

Browse files
fix(plugin-audit, platform-objects): label record pointers "Record" and the import job error "Failure Reason" (#28525)
<!-- claude-projects-attribution: {"github_login":"os-project-manager"} --> _Requested by **Leehom** · [project thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1X1aerzimQKmxjarmWGsK9XD)_ Fixes #28353 Fixes #28113 Clause-②: no Metadata-protocol: none ## 维护者速读 - 改了什么:审计日志(sys_audit_log)与活动(sys_activity)的 `record_id` 字段显示名由 “Record ID” 改为 “Record”(中文 “记录”、日文 “レコード”、西班牙文 “Registro”);导入任务(sys_import_job)的 `error` 字段显示名由 “Fatal Error” 改为 “Failure Reason”(“失败原因”、“失敗理由”、“Motivo del fallo”)。 - 为什么改:审计日志列表和活动详情里这一列画的是目标记录的图标和名称,表头却写 “Record ID”;导入任务全部行失败时 `error` 里是一句 “每行都失败了,原因见结果” 的说明,标成 “Fatal Error” 会让管理员去找一次崩溃。 - 风险与回滚:只改显示名;字段名、类型、存储、查询、种子数据、指针对都不变;回滚即 revert 本 PR。 - 先看:packages/plugins/plugin-audit/src/objects/sys-audit-log.object.ts(record_id 的 label)、packages/platform-objects/src/audit/sys-import-job.object.ts(error 的 label)、packages/plugins/plugin-audit/src/translations/zh-CN.objects.generated.ts(两处 record_id)。 - 两分钟验证:在 Console 打开 Setup › 审计日志,四个列表视图的表头显示 “Record”(中文界面 “记录”);打开任一导入任务记录,Outcome 分组里显示 “Failure Reason”(中文 “失败原因”)。 - 需要你做的:无,席位落地。 ## What changes - `sys_audit_log.record_id` and `sys_activity.record_id` (plugin-audit): label `'Record ID'` becomes `'Record'`. Both are the id half of an ActivityPointer pair (`referenceVia: 'object_name'`), so the console draws the cell as the target record (its object's icon and name) in the audit log's `recent`, `writes_only`, `record_views` and `all_events` list views and on an activity's Details tab. The header now agrees with the cell. `sys_audit_log.record_id`'s `description` ("ID of the affected record") is left as it is: it describes the stored value, and the ruling moves labels only. - `sys_import_job.error` (platform-objects): label `'Fatal Error'` becomes `'Failure Reason'`. Since the every-row-failed ruling the column holds either the fatal error that aborted the job or one sentence pointing at the job's `results`; the spec describe for `ImportJobProgressSchema.error` covers both, and the sibling `protocol.zod.ts` import describe already says "Failure reason, when failed". No other label in the repo names this thing, so the card's example "Failure Reason" was kept. - English bundles regenerated by `node scripts/check-i18n-bundles.mjs --write` (after rebuilding the two packages): across all ten bundle packages, the only diff is the three English leaves above. - Hand translations: zh-CN 记录 ID → 记录, ja-JP レコード ID → レコード, es-ES ID de registro → Registro (the words `sys_approval_action.record_id` and PR #28347 use); zh-CN 致命错误 → 失败原因, ja-JP 致命的なエラー → 失敗理由, es-ES Error fatal → Motivo del fallo. None of these leaves has a source-hash entry in any locale, so no provenance table moves. - `sys_mail_association.record_id` (service-mailbox) keeps "Record ID", as ruled: its record page shows it only in the highlights strip, which prints the stored id. - Changesets: `@objectstack/plugin-audit` patch, `@objectstack/platform-objects` patch. ## Tests - `packages/plugins/plugin-audit/src/sys-audit-log-pointer-pair.test.ts` (where the pair is already pinned): a new block asserts both objects' `record_id` label is "Record", that the field stays the text id half resolved through `object_name`, and that the en / zh-CN / ja-JP / es-ES bundle leaves read Record / 记录 / レコード / Registro. - `packages/platform-objects/src/audit/sys-import-job-error-label.test.ts` (new; no test pinned this object in its package): the `error` label is "Failure Reason", the field stays an optional textarea in the Outcome group, and the four bundle leaves read Failure Reason / 失败原因 / 失敗理由 / Motivo del fallo. - Red first on `main` (`23d1303d`, test commit `56131cbf` only): plugin-audit pointer-pair file 10 failed | 12 passed; import-job file 5 failed (each `Expected "Record"` / `"Failure Reason"`, `Received "Record ID"` / `"Fatal Error"`). Green at the fix: 22/22 and 5/5. ## Acceptance notes - These pins assert display copy, which the order asks for and which this package family already does for labels (`sys-audit-log-action-labels.test.ts`, `sys-notification-display-labels.test.ts`). Each pin also asserts the field's unchanged type and pointer, so a label edit cannot ride along with a storage change. - No open PR touches the edited object or bundle files at the time this PR was opened. ## Verification All readings at head `b0284131` on objectstack-ai/objectstack (merge base `23d1303d`). <details><summary>Tests</summary> - `pnpm --filter @objectstack/plugin-audit test`: Test Files 68/68, Tests 1109/1109 passed (lock VERDICT command-exit 0). - `pnpm --filter @objectstack/platform-objects test`: Test Files 105/105, Tests 1479/1479 passed (lock VERDICT command-exit 0). - `pnpm --filter @objectstack/plugin-audit --filter @objectstack/platform-objects run typecheck` (tsc, scripts tsconfig, test-typecheck ledger 0 held): lock VERDICT command-exit 0. - `eslint packages/plugins/plugin-audit packages/platform-objects --no-inline-config`: exit 0. </details> <details><summary>Gates</summary> - Build: `turbo run build --filter='./packages/**'` 77/77 tasks, lock VERDICT command-exit 0; then the two touched packages rebuilt after the edit. - `dispatch-gates --commands` at `b0284131`: 61 families, each run with stdin from `/dev/null`, exit codes recorded before any pipe; all 61 answered exit 0 (`check-plugin-teardown-shape --self-test` after fetching its pinned control commit `621a4876` into the shallow clone). `--ran`: 61 derived, 61 run, 0 NOT-MEASURED, 0 UNRUN. - The full CI farm (`test:repo`, the UI lanes) is CI's. </details> --- _Generated by [Claude Code](https://claude.ai/code/session_01FEkQ5nRf243Z25ndgeQBPH)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 890c2a6 commit 2c0a97b

15 files changed

Lines changed: 115 additions & 15 deletions
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/platform-objects': patch
3+
---
4+
5+
fix(platform-objects): the import job's `error` field is labelled "Failure Reason", not "Fatal Error"
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
Since a job whose every row failed ends `failed` with one sentence pointing at the job's results, the `error` column holds either the fatal error that aborted the job or that sentence. Headed "Fatal Error", the second case sent an administrator looking for a crash instead of the per-row reasons. The label now covers both outcomes, in the words the spec's import job progress describe uses ("Failure reason"): "Failure Reason", 失败原因 (zh-CN), 失敗理由 (ja-JP), Motivo del fallo (es-ES). Only the label moves: the field stays the same optional text area in the Outcome group.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/plugin-audit': patch
3+
---
4+
5+
fix(plugin-audit): the audit log's and activity's `record_id` field is labelled "Record", not "Record ID"
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
The column shows the target record's name and icon, so the header "Record ID" told an administrator reading the audit log (the `recent`, `writes_only`, `record_views` and `all_events` list views) or an activity's Details tab to look for an id that is not there. The label now reads "Record", and 记录 (zh-CN), レコード (ja-JP) and Registro (es-ES), the words the approval objects already use for their own `record_id`. Only the label moves: the field name `record_id`, its queries, its seeds and its pointer pair with `object_name` are unchanged.

‎packages/platform-objects/src/apps/translations/en.objects.generated.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3061,7 +3061,7 @@ export const enObjects: NonNullable<TranslationData['objects']> = {
30613061
label: "Treat As Historical"
30623062
},
30633063
error: {
3064-
label: "Fatal Error"
3064+
label: "Failure Reason"
30653065
},
30663066
results: {
30673067
label: "Row Results (sample)",

‎packages/platform-objects/src/apps/translations/es-ES.objects.generated.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3061,7 +3061,7 @@ export const esESObjects: NonNullable<TranslationData['objects']> = {
30613061
label: "Tratar como histórico"
30623062
},
30633063
error: {
3064-
label: "Error fatal"
3064+
label: "Motivo del fallo"
30653065
},
30663066
results: {
30673067
label: "Resultados por fila (muestra)",

‎packages/platform-objects/src/apps/translations/ja-JP.objects.generated.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3061,7 +3061,7 @@ export const jaJPObjects: NonNullable<TranslationData['objects']> = {
30613061
label: "履歴データとして扱う"
30623062
},
30633063
error: {
3064-
label: "致命的なエラー"
3064+
label: "失敗理由"
30653065
},
30663066
results: {
30673067
label: "行ごとの結果(サンプル)",

‎packages/platform-objects/src/apps/translations/zh-CN.objects.generated.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3061,7 +3061,7 @@ export const zhCNObjects: NonNullable<TranslationData['objects']> = {
30613061
label: "视为历史数据"
30623062
},
30633063
error: {
3064-
label: "致命错误"
3064+
label: "失败原因"
30653065
},
30663066
results: {
30673067
label: "行结果(样本)",
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
import { describe, it, expect } from 'vitest';
4+
import { SysImportJob } from './sys-import-job.object.js';
5+
import { enObjects } from '../apps/translations/en.objects.generated.js';
6+
import { zhCNObjects } from '../apps/translations/zh-CN.objects.generated.js';
7+
import { jaJPObjects } from '../apps/translations/ja-JP.objects.generated.js';
8+
import { esESObjects } from '../apps/translations/es-ES.objects.generated.js';
9+
10+
/**
11+
* #28113 — the import job's `error` column is headed "Failure Reason".
12+
*
13+
* Since the every-row-failed ruling (#27676), `error` holds either the fatal
14+
* error that aborted the job or, when every row failed, one sentence pointing
15+
* at the job's `results` (`ImportJobProgressSchema.error` describes both).
16+
* Headed "Fatal Error", the second outcome sent an administrator looking for a
17+
* crash. The label now covers both; the field stays the same optional textarea
18+
* in the Outcome group.
19+
*/
20+
describe('sys_import_job.error label (#28113)', () => {
21+
const field = (SysImportJob.fields as Record<string, Record<string, unknown>>).error;
22+
23+
it('is labelled "Failure Reason" and stays an optional textarea in Outcome', () => {
24+
expect(field.label).toBe('Failure Reason');
25+
expect(field.type).toBe('textarea');
26+
expect(field.required ?? false).toBe(false);
27+
expect(field.group).toBe('Outcome');
28+
});
29+
30+
const words = {
31+
en: [enObjects, 'Failure Reason'],
32+
'zh-CN': [zhCNObjects, '失败原因'],
33+
'ja-JP': [jaJPObjects, '失敗理由'],
34+
'es-ES': [esESObjects, 'Motivo del fallo'],
35+
} as const;
36+
37+
for (const [locale, [bundle, word]] of Object.entries(words)) {
38+
it(`reads ${word} in ${locale}`, () => {
39+
const leaf = (bundle as Record<string, { fields?: Record<string, { label?: string }> }>).sys_import_job?.fields?.error;
40+
expect(leaf?.label).toBe(word);
41+
});
42+
}
43+
});

‎packages/platform-objects/src/audit/sys-import-job.object.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export const SysImportJob = ObjectSchema.create({
6767
treat_as_historical: Field.boolean({ label: 'Treat As Historical', required: false, defaultValue: false, group: 'Request' }),
6868

6969
// ── outcome ──
70-
error: Field.textarea({ label: 'Fatal Error', required: false, group: 'Outcome' }),
70+
error: Field.textarea({ label: 'Failure Reason', required: false, group: 'Outcome' }),
7171
results: Field.json({
7272
label: 'Row Results (sample)',
7373
required: false,

‎packages/plugins/plugin-audit/src/objects/sys-activity.object.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ export const SysActivity = ObjectSchema.create({
196196
// registered-but-broken with the ActivityPointer lookup the read path
197197
// assumes (ADR-0052 §5) silently absent.
198198
record_id: Field.text({
199-
label: 'Record ID',
199+
label: 'Record',
200200
required: false,
201201
readonly: true,
202202
searchable: true,

‎packages/plugins/plugin-audit/src/objects/sys-audit-log.object.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ export const SysAuditLog = ObjectSchema.create({
354354
// `ER_BLOB_KEY_WITHOUT_LENGTH`, and the object landed registered-but-broken
355355
// with the lookup its own `record_views` list view depends on absent.
356356
record_id: Field.text({
357-
label: 'Record ID',
357+
label: 'Record',
358358
required: false,
359359
readonly: true,
360360
searchable: true,

0 commit comments

Comments
 (0)