fix(i18n): preserve custom statuses matching inherited alias names

This commit is contained in:
cesnimda
2026-11-02 22:25:09 +01:00
parent 7b132ec4b4
commit 36db932235
3 changed files with 18 additions and 1 deletions
+11
View File
@@ -0,0 +1,11 @@
# Pipeline alias fallback — 2 November 2026
CONFIRMED functional defect: normalizeStatus('constructor') returned the inherited Object function and '__proto__' returned an object instead of the declared pipeline status or Other. statusLabel could consequently lose a custom status. No prototype mutation, account access or persisted-data corruption is asserted.
Minimal fix: only accept own properties of the existing ALIASES map. Existing trimming, case-insensitive canonical stages, known aliases, empty-as-Applied and custom-as-Other behavior are retained. Shared callers include JobFlowBar, KanbanBoard and ApplicationWorkspacePage. No statuses or stored records were renamed; no routes, migrations or dependencies changed.
RED diagnostic: constructor and __proto__ cases failed; toString control passed because the input is lowercased. Eleven unrelated cases were not selected in that diagnostic run. GREEN final: pipeline and grouped-board suites, 29 tests, zero failures/pending, native exit 0. New cases verify raw custom labels bypass translation; existing cases cover aliases, group membership/order, valid stage labels and board interactions. Scoped lint and full typecheck passed. Native ignored report: job-tracker-ui/.artifacts/pipeline-alias-fallback.json.
This resolves historical pipeline.ts:149 `t(LABEL_KEYS[normalized])`: the canonical result is one of the ten explicit LABEL_KEYS or Other, which returns raw status. The original implementation's assumed finite return domain was not true for inherited names. Latest dynamic review count: 123 resolved / 65 pending of 188. Full catalogue/native-language context acceptance is separate.
Rollback: revert the one-line guard and regression additions. Production build from the preceding label/session package predates this patch and is not claimed as a fresh pipeline build. Final integrated browser/security qualification remains open.
+6
View File
@@ -10,6 +10,12 @@ import {
} from './pipeline';
describe('pipeline', () => {
test.each(['constructor', '__proto__', 'toString'])('keeps inherited alias name %s as a custom status', status => {
const translate = jest.fn(() => 'translated');
expect(normalizeStatus(status)).toBe('Other');
expect(statusLabel(translate, status)).toBe(status);
expect(translate).not.toHaveBeenCalled();
});
test('normalizeStatus canonicalizes casing and synonyms', () => {
expect(normalizeStatus('applied')).toBe('Applied');
expect(normalizeStatus(' OFFER ')).toBe('Offer');
+1 -1
View File
@@ -102,7 +102,7 @@ export function normalizeStatus(status?: string | null): PipelineStatus | "Other
const exact = PIPELINE_STATUSES.find((s) => s.toLowerCase() === trimmed.toLowerCase());
if (exact) return exact;
const alias = ALIASES[trimmed.toLowerCase()];
return alias ?? "Other";
return Object.hasOwn(ALIASES, trimmed.toLowerCase()) ? alias : "Other";
}
/** MUI palette key for a status; both chip color and board accent derive from this. */