Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4172c23d7c | |||
| c7e618a548 | |||
| 80d3849125 | |||
| fb48563557 | |||
| 836d36684b | |||
| 4a3da3319e | |||
| fae2f760cd | |||
| 168ccf0b1f | |||
| 3779271ef9 | |||
| 1d68471f0f | |||
| 5d59fd50b6 | |||
| ebd33fcf00 | |||
| e9d68428a2 | |||
| 36db932235 | |||
| 7b132ec4b4 | |||
| 8909e53467 | |||
| 2108ea5037 | |||
| bab240914e | |||
| e563af3e32 | |||
| f577565f71 | |||
| ddf47f7dac | |||
| 1559697eda | |||
| 4939585fb1 |
@@ -0,0 +1,18 @@
|
||||
# Application asset label domains — 2 November 2026
|
||||
|
||||
Nine historical dynamic sites resolved by source review; no source/runtime behavior changed.
|
||||
|
||||
| Historical line(s) | Finite domain / fallback |
|
||||
| --- | --- |
|
||||
| 389 | Package labels iterate only TailoredCvText and RecruiterMessageDraft; the assetsPackage prefix therefore yields two keys. Material body remains user/application data. |
|
||||
| 456/458 | tailoringLabels is a Map of six fixed title/detail tuples; unknown kinds preserve server-supplied title/detail as data. |
|
||||
| 687/688 | historySources and historyAiActions are Maps with five and ten fixed values. Guarded get calls preserve unknown historical source/action labels verbatim. |
|
||||
| 830 | Toolbar iterates four literal key/label pairs. |
|
||||
| 857/895 | COVER_LETTER_ACTIONS is a nine-entry literal array; selection uses find with a fixed coverActionGenerate fallback. |
|
||||
| 866 | Tone options iterate six literal key pairs. |
|
||||
|
||||
All relevant components obtain t from useI18n. The 39 distinct keys across these domains are defined in both catalogues; local assertion verified all 78 definitions. Map lookups have no inherited Object-property ambiguity. UI language and selected document-generation language remain separate. This does not activate AI, re-run PDF metrics or change canonical ownership, revision/history, entitlements, package snapshots or stored text.
|
||||
|
||||
The two error.messageKey sites remain pending until all error constructors/callers are traced. Key-domain review is not complete translator context, professional/native translation review or production capability acceptance. Existing unchanged contract tests were not rerun solely to record these static facts.
|
||||
|
||||
Machine register binds exact expressions and reviewed source hash. Reconciliation: 108 original + 37 supplemental = 145 resolved / 43 pending of 188. Do not count earlier 136/52 as additional work to add to this total.
|
||||
@@ -0,0 +1,20 @@
|
||||
# Attachment preview accessible label — 2026-11-02
|
||||
|
||||
Status: implemented and locally verified; publication recorded in Git history.
|
||||
|
||||
The shared Attachments PDF iframe used the generic English title `pdf`. It now reuses `attachmentsPreviewTitle` with the displayed filename, matching the existing dialog title in English and Norwegian Bokmål. This addresses the generic PDF-title item from the literal review (I00-15).
|
||||
|
||||
Scope: `Attachments.tsx`, its attachment regression tests, and this evidence. ApplicationWorkspacePage remains the caller. No route, API, file-content, upload/download, object-URL lifecycle, persistence, dependency or generated-content language behavior changed.
|
||||
|
||||
Verification:
|
||||
|
||||
- RED: two new language cases failed against the previous generic title; three existing attachment cases passed.
|
||||
- PASSED: attachment and file-picker suites, 13 tests across two suites, zero failures, native exit 0. The language cases open the PDF preview through its translated button and verify the named iframe and blob URL.
|
||||
- PASSED: `npm run typecheck`, exit 0.
|
||||
- PASSED: ESLint for both changed source/test files with zero warnings, exit 0.
|
||||
- An earlier combined test execution passed all 13 assertions but exited 1 because the JSON report directory did not exist. Creating the local artifact directory and rerunning produced the successful execution above. These are overlapping runs, not 26 distinct tests.
|
||||
- Raw successful Jest evidence: local ignored `job-tracker-ui/.artifacts/attachment-label-results.json`.
|
||||
|
||||
Rollback: revert this package; no data conversion is involved. No new translation key was needed. The 80 unresolved dynamic translation calls remain open; this fix does not establish complete i18n or accessibility acceptance. Browser/native assistive-technology checks and a full production build were not rerun for this label-only change.
|
||||
|
||||
Next: continue the unresolved dynamic-call inventory and remaining literal triage; retain all independent workstream and release gates.
|
||||
@@ -0,0 +1,12 @@
|
||||
# Checklist dynamic translation review — 2026-11-02
|
||||
|
||||
Supplement to the historical dynamic inventory; no application behavior changed.
|
||||
|
||||
- RESOLVED: `ApplicationChecklist.tsx:207`, `t(keys[category])`. The local map at lines 200–206 contains five literal keys: checklistCategoryPreparation, checklistCategorySubmission, checklistCategoryFollowUp, checklistCategoryInterview, checklistCategoryCustom. Both English (translations.ts:3042–3046) and Bokmål (6163–6167) define all five. The component obtains `t` from useI18n at line 25 and passes it to the category helper. Unknown categories remain user/domain data displayed verbatim; they never become translation keys.
|
||||
- OPEN: the two checklist-item template calls at lines 214–215 and the two next-step calls in ApplicationWorkspacePage at lines 392/395. `checklistSystemTranslationToken` (applicationWorkspace.ts:94) excludes empty and learning-prefixed keys but otherwise converts arbitrary kebab-case strings. It does not restrict the input to the known translated system items. Catalogue entries alone cannot prove all provider/backend inputs are covered. Inspect the backend system-key producer and compatibility contract before declaring these four calls resolved or changing the fallback.
|
||||
|
||||
Reconciled progress: historical inventory has 188 dynamic calls, 108 previously resolved and 80 pending. This supplemental review resolves one additional call: 109 resolved, 79 pending. The original inventory remains a historical source-bound snapshot; do not add this result to a rerun total or label all translation contexts accepted.
|
||||
|
||||
Evidence: graph query located ApplicationChecklist, useI18n, applicationWorkspace and ApplicationWorkspacePage; direct source review confirmed the map, translator ownership, token behavior and ten catalogue definitions. Static review only; no runtime coverage claim.
|
||||
|
||||
Backend follow-through: ApplicationChecklistService.cs:105–132 defines 14 default system keys. A local assertion converted each through the frontend's kebab-to-camel rule and verified all 28 title/description keys occur in both catalogues (56 definitions). SeedMissingAsync:353–405 adds absent defaults and retains existing persisted rows; Project:482 passes through SystemKey. Learning keys use a separate prefix and remain excluded by the helper. Current defaults are covered; legacy/unrecognised persisted keys still prevent resolving the four calls without a compatibility/fallback decision. No database was accessed.
|
||||
@@ -0,0 +1,13 @@
|
||||
# Historical checklist text fallback
|
||||
|
||||
2 November 2026. CONFIRMED functional compatibility defect: an unknown/retired persisted system key was converted into nonexistent catalogue keys, hiding the supplied historical task text. Diagnostic RED: three unknown-token cases and EN/NB UI cases failed; nine unselected cases were not run in that diagnostic execution.
|
||||
|
||||
Minimal shared fix in checklistSystemTranslationToken: retain kebab-to-camel conversion, but return a token only when the English fallback catalogue owns both title and description keys. Otherwise return null, activating the existing original-text fallback in ApplicationChecklist and workspace next-step presentation. Learning/custom boundaries remain intact. This does not delete tasks, rewrite stored keys/text, change backend generation, enable AI, or change revision/ownership/API contracts. English is the existing reliable translation fallback; current 14 system title/description pairs also exist in Bokmål.
|
||||
|
||||
PASSED: 37 tests in checklist-translation-token, application-checklist and application-workspace-overlay, zero failures/pending, exit 0. New tests prove unknown/inherited-name keys do not manufacture labels, historical text survives EN/NB, and known/learning/null behavior remains. Full typecheck and scoped three-file ESLint passed. Native local report: job-tracker-ui/.artifacts/checklist-unknown-system-keys.json. Full build/browser and integrated security acceptance are not claimed here. Rollback: revert the helper/import and new tests; no database rollback.
|
||||
|
||||
Four dynamic checklist/next-step sites are now bounded by actual catalogue membership, not merely a presumed backend key list. The machine register binds applicationWorkspace.ts as their owner dependency.
|
||||
|
||||
Two further unchanged sites reviewed: ApplicationWorkspacePage.tsx:505 receives only WORKSPACE_SECTIONS.map(s.key), a fixed seven-key label domain; CareerEvidenceBank.tsx:83 first checks a six-value literal category array before constructing the prefixed key, leaving unknown category text untouched. All 41 distinct system/workspace/evidence keys are defined in both catalogues. This is key-domain evidence, not native language quality or complete every-string context.
|
||||
|
||||
Reconciliation: 108 original + 62 supplemental sites = 170 resolved / 18 pending of 188. This supersedes the earlier open checklist gap without reclassifying broader i18n/security acceptance.
|
||||
@@ -0,0 +1,13 @@
|
||||
# Current localisation continuation
|
||||
|
||||
Register portability correction: schema 3 explicitly normalises CRLF to LF when hashing reviewed TS/TSX/JSON text and the original inventory; historicalSourceSha256 retains the original inventory's raw-hash meaning. This avoids treating Git checkout line-ending conversion as a source edit. Integration initially detected the raw inventory mismatch; original snapshot contents and historical source hashes were preserved, and both worktrees are revalidated with the declared encoding. This is evidence portability, not renewed runtime execution.
|
||||
|
||||
2 November 2026. Historical 188 dynamic-call census finite key-domain review COMPLETE; full I18N-00 / European locale release acceptance remains INCOMPLETE. Original source-bound snapshots are retained under 00/. Machine register schema 2 binds inventory indices, source hashes and selected owner dependencies; 108 original plus 80 supplemental calls cover all 188 indices without overlap. Static review does not establish all translator sensitivity/context, every visible/backend string, grammar/plural quality, runtime coverage or native review.
|
||||
|
||||
Independent fixes now include descriptive attachment preview labels; session-change feedback outside private providers; safe inherited-name handling for completeness/timeline/pipeline/processing/interview/purpose labels; and original historical checklist-text fallback for unrecognised system keys. No user data, canonical Career Profile ownership, CV/letter revision or final design contract was rewritten. No dependencies or migrations added.
|
||||
|
||||
Latest implementation qualification: processing monitor 17 tests; checklist/workspace 37 tests; interview/document index 41 tests. Each selected execution passed with zero failures/pending, scoped lint and full typecheck. They are disjoint selected suites, not complete application acceptance. Earlier diagnostic failures and overlapping executions remain separately recorded in their reports. A fresh combined Next 16.4.1 static build after the final fixes passed, exit 0, including TypeScript and all three generated pages. No deployment, live API/provider/model or final integrated security test implied.
|
||||
|
||||
Sanitized native reports: evidence/processing-label-fallbacks.json.gz, evidence/checklist-unknown-system-keys.json.gz, evidence/interview-document-fallbacks.json.gz. Earlier scope reports and prior evidence remain intact. Generated AST graph stays untracked; optional SQL/PDF extractor gaps do not change application acceptance.
|
||||
|
||||
Next independent work: complete direct-access and literal review, every-string context/sensitivity triage, European catalogue/territory/source qualification and approved glossary/translation QA preparation. Full registry/persistence/plural engine architecture still needs prerequisite acceptance and the documented decisions; no proposed locale is published. Native translators/market priorities, Montenegrin tag identity, final design, provider rights, staging/paid scans, hosted CI and production/recovery decisions remain distinct gates. Final integrated security testing follows the relevant application changes.
|
||||
@@ -0,0 +1,13 @@
|
||||
# CV, board and field-review translation domains
|
||||
|
||||
2 November 2026. Eight more historical sites resolved by source/control-flow review; no implementation change or repeated PDF qualification.
|
||||
|
||||
- KanbanBoard.tsx:194/446 iterate the three literal PIPELINE_GROUPS labels. Custom statuses use their separately handled Other column; they do not create group translation keys. The pipeline owner dependency is hash-bound in the register.
|
||||
- CvBuilderEditor.tsx:669 iterates the literal indices 1/0/2/3/4 over five literal studio-tab keys. This lookup is independent of arbitrary tab state.
|
||||
- CvBuilderEditor.tsx:1490 maps four historical sources with an existing Object.hasOwn guard and returns unknown source text as data.
|
||||
- CvBuilderEditor.tsx:486 uses getCvExportFailureKey, which returns only cvEmptyContent/cvPdfBusy/cvPdfTimedOut/undefined after explicit status/code checks. Unrecognised errors use existing error handling. CvBuilderPage.tsx:178 has only four literal action-error constructors plus that same export helper. cvBuilder.ts is recorded as an owner dependency. No server/PDF renderer contract was changed.
|
||||
- CareerProfileSections.tsx:45/46 uses confidenceTone, whose four branches return fixed confidence labels. Confidence is interpolated as data; no confidence value becomes a key. Missing metadata is not presented as an accepted profile fact.
|
||||
|
||||
All components obtain t from useI18n. Assertion verified all 23 distinct keys in both catalogues. This is finite key/control-flow coverage, not native terminology, all placeholders/plurals, semantic CV quality or complete accessibility. Canonical profile ownership, revision-safe document history, source provenance and PDF metric/visual acceptance remain untouched.
|
||||
|
||||
Register reconciliation: 108 original + 56 supplemental sites = 164 resolved / 24 pending of 188. Existing earlier tests are historical evidence for unchanged implementations, not fresh executions by this review.
|
||||
@@ -0,0 +1,917 @@
|
||||
{
|
||||
"schemaVersion": 3,
|
||||
"inventorySha256": "79928688a7b1a4961286aaaf48c028eb13ae8286d72d132561d6b5fdd192e323",
|
||||
"historicalCalls": 188,
|
||||
"previouslyResolved": 108,
|
||||
"additionalResolved": 80,
|
||||
"resolved": 188,
|
||||
"pending": 0,
|
||||
"evidence": [
|
||||
"CHECKLIST_DYNAMIC_REVIEW.md",
|
||||
"FINITE_OWNER_MAP_REVIEW.md",
|
||||
"UNKNOWN_LABEL_FALLBACKS.md",
|
||||
"PIPELINE_ALIAS_FALLBACK.md",
|
||||
"PROCESSING_LABEL_FALLBACKS.md",
|
||||
"REMINDER_INTERVIEW_KEY_REVIEW.md",
|
||||
"ASSET_KEY_REVIEW.md",
|
||||
"LANDING_DOCUMENT_KEY_REVIEW.md",
|
||||
"CV_BOARD_KEY_REVIEW.md",
|
||||
"CHECKLIST_UNKNOWN_SYSTEM_KEYS.md",
|
||||
"ERROR_STATE_KEY_REVIEW.md",
|
||||
"IMPORT_OPERATION_KEY_REVIEW.md",
|
||||
"INTERVIEW_DOCUMENT_FALLBACKS.md"
|
||||
],
|
||||
"entries": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationChecklist.tsx",
|
||||
"historicalLine": 207,
|
||||
"expression": "t(keys[category])",
|
||||
"historicalSourceSha256": "88fdcd24914cf074aedee72a94b0c420c96a16dfe7194142daf22ec0ad8370ff",
|
||||
"reviewedSourceSha256": "0f198e90559b30952cbf7d0f4973211e3fbffcbb183e9e4b4f2ee2e2a9d02f56",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 14
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationIntelligence.tsx",
|
||||
"historicalLine": 367,
|
||||
"expression": "t(keys[category])",
|
||||
"historicalSourceSha256": "89addd1e262ac9c5e37a718acb31d270a132269fe3518d6711e91f3da76ae1a4",
|
||||
"reviewedSourceSha256": "90540576dba4d705ed9234df7091f2b725500d4301287ba151a520956c03f073",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 18
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationIntelligence.tsx",
|
||||
"historicalLine": 373,
|
||||
"expression": "t(`matchScoreBand_${band}`)",
|
||||
"historicalSourceSha256": "89addd1e262ac9c5e37a718acb31d270a132269fe3518d6711e91f3da76ae1a4",
|
||||
"reviewedSourceSha256": "90540576dba4d705ed9234df7091f2b725500d4301287ba151a520956c03f073",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 19
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/CoverLetterDocument.tsx",
|
||||
"historicalLine": 36,
|
||||
"expression": "t(fieldLabels[key])",
|
||||
"historicalSourceSha256": "17ea0c608db7bc05171fb3c44f378c1acaa78fbdd337f9330002ef6346b92546",
|
||||
"reviewedSourceSha256": "d76d0cc3a21230043e91a0d28d03953c236b731c5fecd48e2ba11fd610281053",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 30
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/CoverLetterDocument.tsx",
|
||||
"historicalLine": 153,
|
||||
"expression": "t(fieldLabels[key])",
|
||||
"historicalSourceSha256": "17ea0c608db7bc05171fb3c44f378c1acaa78fbdd337f9330002ef6346b92546",
|
||||
"reviewedSourceSha256": "d76d0cc3a21230043e91a0d28d03953c236b731c5fecd48e2ba11fd610281053",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 33
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/CvTemplateGallery.tsx",
|
||||
"historicalLine": 33,
|
||||
"expression": "t(labels[0])",
|
||||
"historicalSourceSha256": "dda733af709e419b17fb254d65fbb27c8dbba01d032a1c0266517fc27d134eb7",
|
||||
"reviewedSourceSha256": "d7f28fd9479dabd5a988b6a8b656c36c6c9b6622beb13530b7011590edb7965e",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 35
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/CvTemplateGallery.tsx",
|
||||
"historicalLine": 33,
|
||||
"expression": "t(labels[1])",
|
||||
"historicalSourceSha256": "dda733af709e419b17fb254d65fbb27c8dbba01d032a1c0266517fc27d134eb7",
|
||||
"reviewedSourceSha256": "d7f28fd9479dabd5a988b6a8b656c36c6c9b6622beb13530b7011590edb7965e",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 36
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/CvTemplateGallery.tsx",
|
||||
"historicalLine": 33,
|
||||
"expression": "t(labels[2])",
|
||||
"historicalSourceSha256": "dda733af709e419b17fb254d65fbb27c8dbba01d032a1c0266517fc27d134eb7",
|
||||
"reviewedSourceSha256": "d7f28fd9479dabd5a988b6a8b656c36c6c9b6622beb13530b7011590edb7965e",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 37
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/DashboardGrid.tsx",
|
||||
"historicalLine": 47,
|
||||
"expression": "t(WIDGETS.find(widget => widget.id === id)!.titleKey)",
|
||||
"historicalSourceSha256": "201f6d7580af81e92e1fe9c759972a4d2bc1f865cbbe651dd7977e10a130062e",
|
||||
"reviewedSourceSha256": "1f9dfb5dc17b7804c00cca823e7045ec1804d3bcf162bb56590bcd3cf85358d8",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 38
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/DashboardGrid.tsx",
|
||||
"historicalLine": 63,
|
||||
"expression": "t(WIDGETS.find(item => item.id === widget.id)!.titleKey)",
|
||||
"historicalSourceSha256": "201f6d7580af81e92e1fe9c759972a4d2bc1f865cbbe651dd7977e10a130062e",
|
||||
"reviewedSourceSha256": "1f9dfb5dc17b7804c00cca823e7045ec1804d3bcf162bb56590bcd3cf85358d8",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 39
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/DashboardLayoutEditor.tsx",
|
||||
"historicalLine": 77,
|
||||
"expression": "t(entry.titleKey)",
|
||||
"historicalSourceSha256": "faab5c4d63d650c02f4fa0a6f0e2880b1b21535b444a143e1989d9e378f0e16f",
|
||||
"reviewedSourceSha256": "86714ee75bfeddfe62e4c4c9d535c4e641d1213422615fab76838d6aa401984a",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 45
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/DashboardView.tsx",
|
||||
"historicalLine": 259,
|
||||
"expression": "t(key)",
|
||||
"historicalSourceSha256": "37952276ba7d3d0c65df734c816e317b54d50034838dc91f56e3de6f1eb17879",
|
||||
"reviewedSourceSha256": "65113412e4a21e23d093d4af52affab7d24997a3912e7dada9e3e276954d77e0",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 48
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/DashboardView.tsx",
|
||||
"historicalLine": 372,
|
||||
"expression": "t(WIDGETS.find(item => item.id === widget.id)!.titleKey)",
|
||||
"historicalSourceSha256": "37952276ba7d3d0c65df734c816e317b54d50034838dc91f56e3de6f1eb17879",
|
||||
"reviewedSourceSha256": "65113412e4a21e23d093d4af52affab7d24997a3912e7dada9e3e276954d77e0",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 57
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/pipeline.ts",
|
||||
"historicalLine": 149,
|
||||
"expression": "t(LABEL_KEYS[normalized])",
|
||||
"historicalSourceSha256": "fa755ced07a90cef79ceff1622049adc7ed7df3794c942512d9675ef04af8843",
|
||||
"reviewedSourceSha256": "f5cb6d36e81268b2533c4f5ba4e53781007f166c217a4d805c9a8f9f66c2b9ca",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 79
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/AdminProcessingPage.tsx",
|
||||
"historicalLine": 153,
|
||||
"expression": "t(tasks[value])",
|
||||
"historicalSourceSha256": "13973a963ec247c2b61230f5b96ebe1e5feb73ccc9374f15c9bd05f2b3699d1c",
|
||||
"reviewedSourceSha256": "514cbf45298e165334ab502b3833e08fc7a145c5790a80979dc4b0485857316b",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 87
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/AdminProcessingPage.tsx",
|
||||
"historicalLine": 173,
|
||||
"expression": "t(key as TranslationKey)",
|
||||
"historicalSourceSha256": "13973a963ec247c2b61230f5b96ebe1e5feb73ccc9374f15c9bd05f2b3699d1c",
|
||||
"reviewedSourceSha256": "514cbf45298e165334ab502b3833e08fc7a145c5790a80979dc4b0485857316b",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 88
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/AdminProcessingPage.tsx",
|
||||
"historicalLine": 205,
|
||||
"expression": "t(key)",
|
||||
"historicalSourceSha256": "13973a963ec247c2b61230f5b96ebe1e5feb73ccc9374f15c9bd05f2b3699d1c",
|
||||
"reviewedSourceSha256": "514cbf45298e165334ab502b3833e08fc7a145c5790a80979dc4b0485857316b",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 94
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/career/careerCompletenessLabels.ts",
|
||||
"historicalLine": 15,
|
||||
"expression": "t(key)",
|
||||
"historicalSourceSha256": "b841cc4af73307fa33e772b8a10ddfe9620a7566f2b30ef34eb2b832da02d41e",
|
||||
"reviewedSourceSha256": "9e53eab4592a341b6b369b3408843b21b2c9233e9b765115367bb3586a1b8401",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "see named focused regression reports; static review alone is not runtime coverage",
|
||||
"inventoryEntryIndex": 187
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/AdminProcessingPage.tsx",
|
||||
"historicalLine": 130,
|
||||
"expression": "t(statuses[value] ?? 'processingUnknown')",
|
||||
"historicalSourceSha256": "13973a963ec247c2b61230f5b96ebe1e5feb73ccc9374f15c9bd05f2b3699d1c",
|
||||
"reviewedSourceSha256": "514cbf45298e165334ab502b3833e08fc7a145c5790a80979dc4b0485857316b",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "PROCESSING_LABEL_FALLBACKS.md; six inherited-key/language regressions plus eleven existing cases",
|
||||
"inventoryEntryIndex": 80
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/AdminProcessingPage.tsx",
|
||||
"historicalLine": 131,
|
||||
"expression": "t(stages[value])",
|
||||
"historicalSourceSha256": "13973a963ec247c2b61230f5b96ebe1e5feb73ccc9374f15c9bd05f2b3699d1c",
|
||||
"reviewedSourceSha256": "514cbf45298e165334ab502b3833e08fc7a145c5790a80979dc4b0485857316b",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "PROCESSING_LABEL_FALLBACKS.md; six inherited-key/language regressions plus eleven existing cases",
|
||||
"inventoryEntryIndex": 81
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/AdminProcessingPage.tsx",
|
||||
"historicalLine": 175,
|
||||
"expression": "t(tasks[item.taskType] ?? 'processingOther')",
|
||||
"historicalSourceSha256": "13973a963ec247c2b61230f5b96ebe1e5feb73ccc9374f15c9bd05f2b3699d1c",
|
||||
"reviewedSourceSha256": "514cbf45298e165334ab502b3833e08fc7a145c5790a80979dc4b0485857316b",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "PROCESSING_LABEL_FALLBACKS.md; six inherited-key/language regressions plus eleven existing cases",
|
||||
"inventoryEntryIndex": 89
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/AdminProcessingPage.tsx",
|
||||
"historicalLine": 191,
|
||||
"expression": "t(workers[item.name] ?? 'processingWorkerUntracked')",
|
||||
"historicalSourceSha256": "13973a963ec247c2b61230f5b96ebe1e5feb73ccc9374f15c9bd05f2b3699d1c",
|
||||
"reviewedSourceSha256": "514cbf45298e165334ab502b3833e08fc7a145c5790a80979dc4b0485857316b",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "PROCESSING_LABEL_FALLBACKS.md; six inherited-key/language regressions plus eleven existing cases",
|
||||
"inventoryEntryIndex": 91
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/AdminProcessingPage.tsx",
|
||||
"historicalLine": 212,
|
||||
"expression": "t(kinds[item.kind] ?? 'processingUnknown')",
|
||||
"historicalSourceSha256": "13973a963ec247c2b61230f5b96ebe1e5feb73ccc9374f15c9bd05f2b3699d1c",
|
||||
"reviewedSourceSha256": "514cbf45298e165334ab502b3833e08fc7a145c5790a80979dc4b0485857316b",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "PROCESSING_LABEL_FALLBACKS.md; six inherited-key/language regressions plus eleven existing cases",
|
||||
"inventoryEntryIndex": 96
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/InterviewPrep.tsx",
|
||||
"historicalLine": 236,
|
||||
"expression": "t(selected.labelKey)",
|
||||
"historicalSourceSha256": "eadf345d3613ad867788f6a74a8fd1fbba508bb81ec7bc87fe54e4f66dadc69b",
|
||||
"reviewedSourceSha256": "ef8161cc982c9068d3c7eec80f7dd6ef565f05ba0b36bcf58e3b643285b22f0f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static owner-map review only; no inference or provider calls",
|
||||
"inventoryEntryIndex": 63
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/InterviewPrep.tsx",
|
||||
"historicalLine": 261,
|
||||
"expression": "t(selected.labelKey)",
|
||||
"historicalSourceSha256": "eadf345d3613ad867788f6a74a8fd1fbba508bb81ec7bc87fe54e4f66dadc69b",
|
||||
"reviewedSourceSha256": "ef8161cc982c9068d3c7eec80f7dd6ef565f05ba0b36bcf58e3b643285b22f0f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static owner-map review only; no inference or provider calls",
|
||||
"inventoryEntryIndex": 64
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/InterviewPrep.tsx",
|
||||
"historicalLine": 285,
|
||||
"expression": "t(item.labelKey)",
|
||||
"historicalSourceSha256": "eadf345d3613ad867788f6a74a8fd1fbba508bb81ec7bc87fe54e4f66dadc69b",
|
||||
"reviewedSourceSha256": "ef8161cc982c9068d3c7eec80f7dd6ef565f05ba0b36bcf58e3b643285b22f0f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static owner-map review only; no inference or provider calls",
|
||||
"inventoryEntryIndex": 65
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/RemindersView.tsx",
|
||||
"historicalLine": 35,
|
||||
"expression": "t(key)",
|
||||
"historicalSourceSha256": "1eedbc443761001e86be1f322691ab4058553033e764b0c6cf9c93ce4fab05c0",
|
||||
"reviewedSourceSha256": "e550e76cb28cb4236100bb1a35158a329e4ecd3a12be56f6cdaf28fb75fa0091",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static owner-map review only; no inference or provider calls",
|
||||
"inventoryEntryIndex": 76
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/RemindersView.tsx",
|
||||
"historicalLine": 38,
|
||||
"expression": "t(dayKey, { days: match[1] })",
|
||||
"historicalSourceSha256": "1eedbc443761001e86be1f322691ab4058553033e764b0c6cf9c93ce4fab05c0",
|
||||
"reviewedSourceSha256": "e550e76cb28cb4236100bb1a35158a329e4ecd3a12be56f6cdaf28fb75fa0091",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static owner-map review only; no inference or provider calls",
|
||||
"inventoryEntryIndex": 77
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"historicalLine": 389,
|
||||
"expression": "t(`assetsPackage${key}` as \"assetsPackageTailoredCvText\")",
|
||||
"historicalSourceSha256": "25216c80ef92d519baad9e428a0e77390150605c1a3529a4809819d120661f29",
|
||||
"reviewedSourceSha256": "b5f14b41de10474e2bcd709b91b1becb7b7db4aba021fba29e4e9e44a7a2947f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static owner-map review; no AI inference or provider calls",
|
||||
"inventoryEntryIndex": 4
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"historicalLine": 456,
|
||||
"expression": "t(labels[0])",
|
||||
"historicalSourceSha256": "25216c80ef92d519baad9e428a0e77390150605c1a3529a4809819d120661f29",
|
||||
"reviewedSourceSha256": "b5f14b41de10474e2bcd709b91b1becb7b7db4aba021fba29e4e9e44a7a2947f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static owner-map review; no AI inference or provider calls",
|
||||
"inventoryEntryIndex": 5
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"historicalLine": 458,
|
||||
"expression": "t(labels[1])",
|
||||
"historicalSourceSha256": "25216c80ef92d519baad9e428a0e77390150605c1a3529a4809819d120661f29",
|
||||
"reviewedSourceSha256": "b5f14b41de10474e2bcd709b91b1becb7b7db4aba021fba29e4e9e44a7a2947f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static owner-map review; no AI inference or provider calls",
|
||||
"inventoryEntryIndex": 6
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"historicalLine": 687,
|
||||
"expression": "t(sourceKey)",
|
||||
"historicalSourceSha256": "25216c80ef92d519baad9e428a0e77390150605c1a3529a4809819d120661f29",
|
||||
"reviewedSourceSha256": "b5f14b41de10474e2bcd709b91b1becb7b7db4aba021fba29e4e9e44a7a2947f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static owner-map review; no AI inference or provider calls",
|
||||
"inventoryEntryIndex": 7
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"historicalLine": 688,
|
||||
"expression": "t(actionKey)",
|
||||
"historicalSourceSha256": "25216c80ef92d519baad9e428a0e77390150605c1a3529a4809819d120661f29",
|
||||
"reviewedSourceSha256": "b5f14b41de10474e2bcd709b91b1becb7b7db4aba021fba29e4e9e44a7a2947f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static owner-map review; no AI inference or provider calls",
|
||||
"inventoryEntryIndex": 8
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"historicalLine": 830,
|
||||
"expression": "t(label)",
|
||||
"historicalSourceSha256": "25216c80ef92d519baad9e428a0e77390150605c1a3529a4809819d120661f29",
|
||||
"reviewedSourceSha256": "b5f14b41de10474e2bcd709b91b1becb7b7db4aba021fba29e4e9e44a7a2947f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static owner-map review; no AI inference or provider calls",
|
||||
"inventoryEntryIndex": 9
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"historicalLine": 857,
|
||||
"expression": "t(item.labelKey)",
|
||||
"historicalSourceSha256": "25216c80ef92d519baad9e428a0e77390150605c1a3529a4809819d120661f29",
|
||||
"reviewedSourceSha256": "b5f14b41de10474e2bcd709b91b1becb7b7db4aba021fba29e4e9e44a7a2947f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static owner-map review; no AI inference or provider calls",
|
||||
"inventoryEntryIndex": 10
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"historicalLine": 866,
|
||||
"expression": "t(key as any)",
|
||||
"historicalSourceSha256": "25216c80ef92d519baad9e428a0e77390150605c1a3529a4809819d120661f29",
|
||||
"reviewedSourceSha256": "b5f14b41de10474e2bcd709b91b1becb7b7db4aba021fba29e4e9e44a7a2947f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static owner-map review; no AI inference or provider calls",
|
||||
"inventoryEntryIndex": 11
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"historicalLine": 895,
|
||||
"expression": "t(COVER_LETTER_ACTIONS.find((item) => item.key === action)?.labelKey ?? \"coverActionGenerate\")",
|
||||
"historicalSourceSha256": "25216c80ef92d519baad9e428a0e77390150605c1a3529a4809819d120661f29",
|
||||
"reviewedSourceSha256": "b5f14b41de10474e2bcd709b91b1becb7b7db4aba021fba29e4e9e44a7a2947f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static owner-map review; no AI inference or provider calls",
|
||||
"inventoryEntryIndex": 13
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/DocumentsPage.tsx",
|
||||
"historicalLine": 222,
|
||||
"expression": "t(label)",
|
||||
"historicalSourceSha256": "fa53a826ebbdbc868c8b21a0387138c12611d3e2867de0fa0e5f6d8483471eb9",
|
||||
"reviewedSourceSha256": "0b9aaba2c102b4346b10386107b3822016b4f680bb9ab6b58c24ef80b74080fc",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static source review; no marketing or accessibility acceptance",
|
||||
"inventoryEntryIndex": 134
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/DocumentsPage.tsx",
|
||||
"historicalLine": 225,
|
||||
"expression": "t(states.find(([value]) => value === item.state)?.[1] ?? \"documentsCurrent\")",
|
||||
"historicalSourceSha256": "fa53a826ebbdbc868c8b21a0387138c12611d3e2867de0fa0e5f6d8483471eb9",
|
||||
"reviewedSourceSha256": "0b9aaba2c102b4346b10386107b3822016b4f680bb9ab6b58c24ef80b74080fc",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static source review; no marketing or accessibility acceptance",
|
||||
"inventoryEntryIndex": 135
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/DocumentsPage.tsx",
|
||||
"historicalLine": 231,
|
||||
"expression": "t(types.find(([value]) => value === item.type)?.[1] ?? \"documentsTypeAttachment\")",
|
||||
"historicalSourceSha256": "fa53a826ebbdbc868c8b21a0387138c12611d3e2867de0fa0e5f6d8483471eb9",
|
||||
"reviewedSourceSha256": "0b9aaba2c102b4346b10386107b3822016b4f680bb9ab6b58c24ef80b74080fc",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static source review; no marketing or accessibility acceptance",
|
||||
"inventoryEntryIndex": 137
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/DocumentsPage.tsx",
|
||||
"historicalLine": 264,
|
||||
"expression": "t(title)",
|
||||
"historicalSourceSha256": "fa53a826ebbdbc868c8b21a0387138c12611d3e2867de0fa0e5f6d8483471eb9",
|
||||
"reviewedSourceSha256": "0b9aaba2c102b4346b10386107b3822016b4f680bb9ab6b58c24ef80b74080fc",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static source review; no marketing or accessibility acceptance",
|
||||
"inventoryEntryIndex": 144
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/DocumentsPage.tsx",
|
||||
"historicalLine": 265,
|
||||
"expression": "t(title)",
|
||||
"historicalSourceSha256": "fa53a826ebbdbc868c8b21a0387138c12611d3e2867de0fa0e5f6d8483471eb9",
|
||||
"reviewedSourceSha256": "0b9aaba2c102b4346b10386107b3822016b4f680bb9ab6b58c24ef80b74080fc",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static source review; no marketing or accessibility acceptance",
|
||||
"inventoryEntryIndex": 145
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/DocumentsPage.tsx",
|
||||
"historicalLine": 265,
|
||||
"expression": "t(label)",
|
||||
"historicalSourceSha256": "fa53a826ebbdbc868c8b21a0387138c12611d3e2867de0fa0e5f6d8483471eb9",
|
||||
"reviewedSourceSha256": "0b9aaba2c102b4346b10386107b3822016b4f680bb9ab6b58c24ef80b74080fc",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static source review; no marketing or accessibility acceptance",
|
||||
"inventoryEntryIndex": 146
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/LandingPage.tsx",
|
||||
"historicalLine": 87,
|
||||
"expression": "t(`landingPlan${plan.id === \"free\" ? \"Free\" : \"Pro\"}Feature${index + 1}` as TranslationKey)",
|
||||
"historicalSourceSha256": "2c550aa126e1db8786ed10b895d2403491ce50bf5073fc95b8a0fcb0cb0e083e",
|
||||
"reviewedSourceSha256": "aedcdbc8bfc22f7cd4bc9737a06b07f318ca7b4970836bd6c20e805ebfa36c74",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static source review; no marketing or accessibility acceptance",
|
||||
"ownerDependencies": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/planCatalog.ts",
|
||||
"sha256": "068871cc43669d6f8a0581fbaefe8e6d0d2ab7f1c47e0b31cb131e767c2d13b2"
|
||||
}
|
||||
],
|
||||
"inventoryEntryIndex": 160
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/LandingPage.tsx",
|
||||
"historicalLine": 172,
|
||||
"expression": "t(f.title)",
|
||||
"historicalSourceSha256": "2c550aa126e1db8786ed10b895d2403491ce50bf5073fc95b8a0fcb0cb0e083e",
|
||||
"reviewedSourceSha256": "aedcdbc8bfc22f7cd4bc9737a06b07f318ca7b4970836bd6c20e805ebfa36c74",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static source review; no marketing or accessibility acceptance",
|
||||
"ownerDependencies": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/planCatalog.ts",
|
||||
"sha256": "068871cc43669d6f8a0581fbaefe8e6d0d2ab7f1c47e0b31cb131e767c2d13b2"
|
||||
}
|
||||
],
|
||||
"inventoryEntryIndex": 162
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/LandingPage.tsx",
|
||||
"historicalLine": 173,
|
||||
"expression": "t(f.body)",
|
||||
"historicalSourceSha256": "2c550aa126e1db8786ed10b895d2403491ce50bf5073fc95b8a0fcb0cb0e083e",
|
||||
"reviewedSourceSha256": "aedcdbc8bfc22f7cd4bc9737a06b07f318ca7b4970836bd6c20e805ebfa36c74",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static source review; no marketing or accessibility acceptance",
|
||||
"ownerDependencies": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/planCatalog.ts",
|
||||
"sha256": "068871cc43669d6f8a0581fbaefe8e6d0d2ab7f1c47e0b31cb131e767c2d13b2"
|
||||
}
|
||||
],
|
||||
"inventoryEntryIndex": 163
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/LandingPage.tsx",
|
||||
"historicalLine": 190,
|
||||
"expression": "t(s.title)",
|
||||
"historicalSourceSha256": "2c550aa126e1db8786ed10b895d2403491ce50bf5073fc95b8a0fcb0cb0e083e",
|
||||
"reviewedSourceSha256": "aedcdbc8bfc22f7cd4bc9737a06b07f318ca7b4970836bd6c20e805ebfa36c74",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static source review; no marketing or accessibility acceptance",
|
||||
"ownerDependencies": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/planCatalog.ts",
|
||||
"sha256": "068871cc43669d6f8a0581fbaefe8e6d0d2ab7f1c47e0b31cb131e767c2d13b2"
|
||||
}
|
||||
],
|
||||
"inventoryEntryIndex": 164
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/LandingPage.tsx",
|
||||
"historicalLine": 191,
|
||||
"expression": "t(s.body)",
|
||||
"historicalSourceSha256": "2c550aa126e1db8786ed10b895d2403491ce50bf5073fc95b8a0fcb0cb0e083e",
|
||||
"reviewedSourceSha256": "aedcdbc8bfc22f7cd4bc9737a06b07f318ca7b4970836bd6c20e805ebfa36c74",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static source review; no marketing or accessibility acceptance",
|
||||
"ownerDependencies": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/planCatalog.ts",
|
||||
"sha256": "068871cc43669d6f8a0581fbaefe8e6d0d2ab7f1c47e0b31cb131e767c2d13b2"
|
||||
}
|
||||
],
|
||||
"inventoryEntryIndex": 165
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/KanbanBoard.tsx",
|
||||
"historicalLine": 194,
|
||||
"expression": "t(g.labelKey as any)",
|
||||
"historicalSourceSha256": "f9e7491cd3bd82214fb081571b46b55b31fb8e135fa5050e76896759c2e79a92",
|
||||
"reviewedSourceSha256": "e83ea475bbf1f33fd262bff154d3cbe8a4b20815beaa00b48312377663f4e48e",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static control-flow review; no PDF metric or model rerun",
|
||||
"ownerDependencies": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/pipeline.ts",
|
||||
"sha256": "f5cb6d36e81268b2533c4f5ba4e53781007f166c217a4d805c9a8f9f66c2b9ca"
|
||||
}
|
||||
],
|
||||
"inventoryEntryIndex": 71
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/KanbanBoard.tsx",
|
||||
"historicalLine": 446,
|
||||
"expression": "t(g.labelKey as any)",
|
||||
"historicalSourceSha256": "f9e7491cd3bd82214fb081571b46b55b31fb8e135fa5050e76896759c2e79a92",
|
||||
"reviewedSourceSha256": "e83ea475bbf1f33fd262bff154d3cbe8a4b20815beaa00b48312377663f4e48e",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static control-flow review; no PDF metric or model rerun",
|
||||
"ownerDependencies": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/pipeline.ts",
|
||||
"sha256": "f5cb6d36e81268b2533c4f5ba4e53781007f166c217a4d805c9a8f9f66c2b9ca"
|
||||
}
|
||||
],
|
||||
"inventoryEntryIndex": 74
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/CvBuilderEditor.tsx",
|
||||
"historicalLine": 486,
|
||||
"expression": "t(key)",
|
||||
"historicalSourceSha256": "b163cbe792e98cc1afdd775ffb595c1abb8b58c5fdd9a79bbd6fa6b552f868ae",
|
||||
"reviewedSourceSha256": "67d091b653ca151be853746eaaca1fd5d159a5670924705e228d8e2e9327ad0f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static control-flow review; no PDF metric or model rerun",
|
||||
"ownerDependencies": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/cvBuilder.ts",
|
||||
"sha256": "c021bafeabbc8ad3526d1b10b90ad8f7f0958ded8ed26eac8c1d28b53098b64d"
|
||||
}
|
||||
],
|
||||
"inventoryEntryIndex": 116
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/CvBuilderEditor.tsx",
|
||||
"historicalLine": 669,
|
||||
"expression": "t(([\"cvEditorTemplate\", \"cvEditorContent\", \"cvEditorCustomize\", \"cvEditorAiTools\", \"cvEditorHistory\"] as const)[value])",
|
||||
"historicalSourceSha256": "b163cbe792e98cc1afdd775ffb595c1abb8b58c5fdd9a79bbd6fa6b552f868ae",
|
||||
"reviewedSourceSha256": "67d091b653ca151be853746eaaca1fd5d159a5670924705e228d8e2e9327ad0f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static control-flow review; no PDF metric or model rerun",
|
||||
"inventoryEntryIndex": 117
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/CvBuilderEditor.tsx",
|
||||
"historicalLine": 1490,
|
||||
"expression": "t(source)",
|
||||
"historicalSourceSha256": "b163cbe792e98cc1afdd775ffb595c1abb8b58c5fdd9a79bbd6fa6b552f868ae",
|
||||
"reviewedSourceSha256": "67d091b653ca151be853746eaaca1fd5d159a5670924705e228d8e2e9327ad0f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static control-flow review; no PDF metric or model rerun",
|
||||
"inventoryEntryIndex": 131
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/CvBuilderPage.tsx",
|
||||
"historicalLine": 178,
|
||||
"expression": "t(actionError.key)",
|
||||
"historicalSourceSha256": "b4cc784cadb3b820b78b7b688e3c9961ed724230de4fc5fffae166d29620f361",
|
||||
"reviewedSourceSha256": "d9b7ece2ff25d082bdd8d109f52bb2342d9071b8cc465ca5a2b15ac20aeac6c6",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static control-flow review; no PDF metric or model rerun",
|
||||
"ownerDependencies": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/cvBuilder.ts",
|
||||
"sha256": "c021bafeabbc8ad3526d1b10b90ad8f7f0958ded8ed26eac8c1d28b53098b64d"
|
||||
}
|
||||
],
|
||||
"inventoryEntryIndex": 132
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/career/CareerProfileSections.tsx",
|
||||
"historicalLine": 45,
|
||||
"expression": "t(tone.key, { percent: Math.round(metadata.confidence * 100) })",
|
||||
"historicalSourceSha256": "0c772feb6bde8324676b0884aaf343283465c5cd3b3318128363063df4ea22ab",
|
||||
"reviewedSourceSha256": "aa3acbe472d34074a517a566c77983e7d95f8ec1df9ee37e47537ad96beffd0e",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static control-flow review; no PDF metric or model rerun",
|
||||
"inventoryEntryIndex": 176
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/career/CareerProfileSections.tsx",
|
||||
"historicalLine": 46,
|
||||
"expression": "t(tone.key)",
|
||||
"historicalSourceSha256": "0c772feb6bde8324676b0884aaf343283465c5cd3b3318128363063df4ea22ab",
|
||||
"reviewedSourceSha256": "aa3acbe472d34074a517a566c77983e7d95f8ec1df9ee37e47537ad96beffd0e",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static control-flow review; no PDF metric or model rerun",
|
||||
"inventoryEntryIndex": 177
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationChecklist.tsx",
|
||||
"historicalLine": 214,
|
||||
"expression": "t(`checklistItem_${token}`)",
|
||||
"historicalSourceSha256": "88fdcd24914cf074aedee72a94b0c420c96a16dfe7194142daf22ec0ad8370ff",
|
||||
"reviewedSourceSha256": "0f198e90559b30952cbf7d0f4973211e3fbffcbb183e9e4b4f2ee2e2a9d02f56",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "CHECKLIST_UNKNOWN_SYSTEM_KEYS.md; 37 focused cases; other finite labels statically reviewed",
|
||||
"ownerDependencies": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/applicationWorkspace.ts",
|
||||
"sha256": "3b00a4fe16159bdb9603eeb37bfdf5e5eb9a87d7815227fa3aa2f0da6e4f232c"
|
||||
}
|
||||
],
|
||||
"inventoryEntryIndex": 15
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationChecklist.tsx",
|
||||
"historicalLine": 215,
|
||||
"expression": "t(`checklistItem_${token}Description`)",
|
||||
"historicalSourceSha256": "88fdcd24914cf074aedee72a94b0c420c96a16dfe7194142daf22ec0ad8370ff",
|
||||
"reviewedSourceSha256": "0f198e90559b30952cbf7d0f4973211e3fbffcbb183e9e4b4f2ee2e2a9d02f56",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "CHECKLIST_UNKNOWN_SYSTEM_KEYS.md; 37 focused cases; other finite labels statically reviewed",
|
||||
"ownerDependencies": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/applicationWorkspace.ts",
|
||||
"sha256": "3b00a4fe16159bdb9603eeb37bfdf5e5eb9a87d7815227fa3aa2f0da6e4f232c"
|
||||
}
|
||||
],
|
||||
"inventoryEntryIndex": 16
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/ApplicationWorkspacePage.tsx",
|
||||
"historicalLine": 392,
|
||||
"expression": "t(`checklistItem_${nextStepToken}` as any)",
|
||||
"historicalSourceSha256": "107b4db54ef15d88254e01bc404136b987755588c1d171b800c2a47f93488b50",
|
||||
"reviewedSourceSha256": "62c79d59ce31dccddefd70991db5fc26fcc84f0c58ca6219d0d36980db2050d7",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "CHECKLIST_UNKNOWN_SYSTEM_KEYS.md; 37 focused cases; other finite labels statically reviewed",
|
||||
"ownerDependencies": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/applicationWorkspace.ts",
|
||||
"sha256": "3b00a4fe16159bdb9603eeb37bfdf5e5eb9a87d7815227fa3aa2f0da6e4f232c"
|
||||
}
|
||||
],
|
||||
"inventoryEntryIndex": 101
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/ApplicationWorkspacePage.tsx",
|
||||
"historicalLine": 395,
|
||||
"expression": "t(`checklistItem_${nextStepToken}Description` as any)",
|
||||
"historicalSourceSha256": "107b4db54ef15d88254e01bc404136b987755588c1d171b800c2a47f93488b50",
|
||||
"reviewedSourceSha256": "62c79d59ce31dccddefd70991db5fc26fcc84f0c58ca6219d0d36980db2050d7",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "CHECKLIST_UNKNOWN_SYSTEM_KEYS.md; 37 focused cases; other finite labels statically reviewed",
|
||||
"ownerDependencies": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/applicationWorkspace.ts",
|
||||
"sha256": "3b00a4fe16159bdb9603eeb37bfdf5e5eb9a87d7815227fa3aa2f0da6e4f232c"
|
||||
}
|
||||
],
|
||||
"inventoryEntryIndex": 102
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/ApplicationWorkspacePage.tsx",
|
||||
"historicalLine": 505,
|
||||
"expression": "t(keys[section])",
|
||||
"historicalSourceSha256": "107b4db54ef15d88254e01bc404136b987755588c1d171b800c2a47f93488b50",
|
||||
"reviewedSourceSha256": "62c79d59ce31dccddefd70991db5fc26fcc84f0c58ca6219d0d36980db2050d7",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "CHECKLIST_UNKNOWN_SYSTEM_KEYS.md; 37 focused cases; other finite labels statically reviewed",
|
||||
"ownerDependencies": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/applicationWorkspace.ts",
|
||||
"sha256": "3b00a4fe16159bdb9603eeb37bfdf5e5eb9a87d7815227fa3aa2f0da6e4f232c"
|
||||
}
|
||||
],
|
||||
"inventoryEntryIndex": 103
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/career/CareerEvidenceBank.tsx",
|
||||
"historicalLine": 83,
|
||||
"expression": "t(`careerEvidenceCategory_${value}` as \"careerEvidenceCategory_achievement\")",
|
||||
"historicalSourceSha256": "fc85ccfc1addd48af3a29bc263b089858765b2ac3ec7db3b66dedc55ddfab625",
|
||||
"reviewedSourceSha256": "51cab7289717c9f26006a9d34ac1f8aac9e09d19e549a3666a15adc41d5d4724",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "CHECKLIST_UNKNOWN_SYSTEM_KEYS.md; 37 focused cases; other finite labels statically reviewed",
|
||||
"inventoryEntryIndex": 175
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 2,
|
||||
"file": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"historicalLine": 104,
|
||||
"expression": "t(error.messageKey)",
|
||||
"historicalSourceSha256": "25216c80ef92d519baad9e428a0e77390150605c1a3529a4809819d120661f29",
|
||||
"reviewedSourceSha256": "b5f14b41de10474e2bcd709b91b1becb7b7db4aba021fba29e4e9e44a7a2947f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static state-constructor and own-property review; no admin actions, external mail or AI executed"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 12,
|
||||
"file": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"historicalLine": 887,
|
||||
"expression": "t(error.messageKey)",
|
||||
"historicalSourceSha256": "25216c80ef92d519baad9e428a0e77390150605c1a3529a4809819d120661f29",
|
||||
"reviewedSourceSha256": "b5f14b41de10474e2bcd709b91b1becb7b7db4aba021fba29e4e9e44a7a2947f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static state-constructor and own-property review; no admin actions, external mail or AI executed"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 97,
|
||||
"file": "job-tracker-ui/src/views/AdminSystemPage.tsx",
|
||||
"historicalLine": 333,
|
||||
"expression": "t(kind === \"status\" && status ? \"adminSystemRefreshFailed\" : readErrorKeys[kind])",
|
||||
"historicalSourceSha256": "1e76931739d779d9edb17e22846d16fffef7ebd1a0c27aebf740c2c46c79b3de",
|
||||
"reviewedSourceSha256": "64e85d9b13088b5229b6635674e9e6ff9ee6c4a62db7f66accb1dcddcedd16c0",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static state-constructor and own-property review; no admin actions, external mail or AI executed"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 98,
|
||||
"file": "job-tracker-ui/src/views/AdminSystemPage.tsx",
|
||||
"historicalLine": 448,
|
||||
"expression": "t(actionErrorKeys[actionError.kind])",
|
||||
"historicalSourceSha256": "1e76931739d779d9edb17e22846d16fffef7ebd1a0c27aebf740c2c46c79b3de",
|
||||
"reviewedSourceSha256": "64e85d9b13088b5229b6635674e9e6ff9ee6c4a62db7f66accb1dcddcedd16c0",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static state-constructor and own-property review; no admin actions, external mail or AI executed"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 99,
|
||||
"file": "job-tracker-ui/src/views/AdminSystemPage.tsx",
|
||||
"historicalLine": 449,
|
||||
"expression": "t(message)",
|
||||
"historicalSourceSha256": "1e76931739d779d9edb17e22846d16fffef7ebd1a0c27aebf740c2c46c79b3de",
|
||||
"reviewedSourceSha256": "64e85d9b13088b5229b6635674e9e6ff9ee6c4a62db7f66accb1dcddcedd16c0",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static state-constructor and own-property review; no admin actions, external mail or AI executed"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 104,
|
||||
"file": "job-tracker-ui/src/views/CareerProfilePage.tsx",
|
||||
"historicalLine": 508,
|
||||
"expression": "t(stageKeys[stage])",
|
||||
"historicalSourceSha256": "d8f302c2bd8b09544a41735b4d63818c2843ca5193f7b733a3e8447c828f181a",
|
||||
"reviewedSourceSha256": "190b8b0840fb57480985a1688160001a1e5e828639e5b632351740b6352da0b7",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static state-constructor and own-property review; no admin actions, external mail or AI executed"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 105,
|
||||
"file": "job-tracker-ui/src/views/CareerProfilePage.tsx",
|
||||
"historicalLine": 509,
|
||||
"expression": "t(importLabelKeys[value])",
|
||||
"historicalSourceSha256": "d8f302c2bd8b09544a41735b4d63818c2843ca5193f7b733a3e8447c828f181a",
|
||||
"reviewedSourceSha256": "190b8b0840fb57480985a1688160001a1e5e828639e5b632351740b6352da0b7",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static state-constructor and own-property review; no admin actions, external mail or AI executed"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 106,
|
||||
"file": "job-tracker-ui/src/views/CareerProfilePage.tsx",
|
||||
"historicalLine": 865,
|
||||
"expression": "t(runActionErrors[run.id].key)",
|
||||
"historicalSourceSha256": "d8f302c2bd8b09544a41735b4d63818c2843ca5193f7b733a3e8447c828f181a",
|
||||
"reviewedSourceSha256": "190b8b0840fb57480985a1688160001a1e5e828639e5b632351740b6352da0b7",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static state-constructor and own-property review; no admin actions, external mail or AI executed"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 153,
|
||||
"file": "job-tracker-ui/src/views/GmailReviewPage.tsx",
|
||||
"historicalLine": 231,
|
||||
"expression": "t(writeError.key)",
|
||||
"historicalSourceSha256": "3609ec12dd9619f7cbbd3541dcf2563a33e4ef3cb7cf9eab0cfc4a17a43d22d8",
|
||||
"reviewedSourceSha256": "5e87cad1c5f5118fdd6d62d3aae35b83b3ab10d8d60722ed18c1dbb4487f9890",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static state-constructor and own-property review; no admin actions, external mail or AI executed"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 154,
|
||||
"file": "job-tracker-ui/src/views/GmailReviewPage.tsx",
|
||||
"historicalLine": 231,
|
||||
"expression": "t(writeError.key)",
|
||||
"historicalSourceSha256": "3609ec12dd9619f7cbbd3541dcf2563a33e4ef3cb7cf9eab0cfc4a17a43d22d8",
|
||||
"reviewedSourceSha256": "5e87cad1c5f5118fdd6d62d3aae35b83b3ab10d8d60722ed18c1dbb4487f9890",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static state-constructor and own-property review; no admin actions, external mail or AI executed"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 155,
|
||||
"file": "job-tracker-ui/src/views/JobDiscoveryPage.tsx",
|
||||
"historicalLine": 229,
|
||||
"expression": "t(error ?? \"jobDiscoveryUnavailable\")",
|
||||
"historicalSourceSha256": "e15f5183fe6d41ecb7a53ec9806872a67f0d6ce683354d0abef53527bd397b94",
|
||||
"reviewedSourceSha256": "8055c95959b662b69f04f780993d4668e3907c53b445451c0981fa3a1436756f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static state-constructor and own-property review; no admin actions, external mail or AI executed"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 156,
|
||||
"file": "job-tracker-ui/src/views/JobDiscoveryPage.tsx",
|
||||
"historicalLine": 230,
|
||||
"expression": "t(error)",
|
||||
"historicalSourceSha256": "e15f5183fe6d41ecb7a53ec9806872a67f0d6ce683354d0abef53527bd397b94",
|
||||
"reviewedSourceSha256": "8055c95959b662b69f04f780993d4668e3907c53b445451c0981fa3a1436756f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "static state-constructor and own-property review; no admin actions, external mail or AI executed"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 166,
|
||||
"file": "job-tracker-ui/src/views/OperationsPage.tsx",
|
||||
"historicalLine": 127,
|
||||
"expression": "t(taskKeys[task])",
|
||||
"historicalSourceSha256": "8cff1e08b2009ff683957849af71d6e76916a28ae218e647d9e3c04a12ad5f9b",
|
||||
"reviewedSourceSha256": "b35c793fd33dcd0638d47df2aa3bfb2926879a8fa709880983b64c1a1309bb98",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "existing Object.hasOwn guards statically reviewed; no service execution"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 168,
|
||||
"file": "job-tracker-ui/src/views/OperationsPage.tsx",
|
||||
"historicalLine": 158,
|
||||
"expression": "t(statusKeys[operation.status])",
|
||||
"historicalSourceSha256": "8cff1e08b2009ff683957849af71d6e76916a28ae218e647d9e3c04a12ad5f9b",
|
||||
"reviewedSourceSha256": "b35c793fd33dcd0638d47df2aa3bfb2926879a8fa709880983b64c1a1309bb98",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "existing Object.hasOwn guards statically reviewed; no service execution"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 183,
|
||||
"file": "job-tracker-ui/src/views/career/CvImportReview.tsx",
|
||||
"historicalLine": 114,
|
||||
"expression": "t(labelKeys[value])",
|
||||
"historicalSourceSha256": "bdecd17437d919a33d9deaa855262b1f1baf78b4a22eef0e88ac1fdbb5ebeda4",
|
||||
"reviewedSourceSha256": "dbbf0bcebd4fc46f55deaa6bb70a0abd37ecb0f01608335bcaf4de46e05f4a48",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "existing Object.hasOwn guards statically reviewed; no service execution"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 184,
|
||||
"file": "job-tracker-ui/src/views/career/CvImportReview.tsx",
|
||||
"historicalLine": 165,
|
||||
"expression": "t(warningKeys[warning])",
|
||||
"historicalSourceSha256": "bdecd17437d919a33d9deaa855262b1f1baf78b4a22eef0e88ac1fdbb5ebeda4",
|
||||
"reviewedSourceSha256": "dbbf0bcebd4fc46f55deaa6bb70a0abd37ecb0f01608335bcaf4de46e05f4a48",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "existing Object.hasOwn guards statically reviewed; no service execution"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 67,
|
||||
"file": "job-tracker-ui/src/components/InterviewPrep.tsx",
|
||||
"historicalLine": 505,
|
||||
"expression": "t(keys[category])",
|
||||
"historicalSourceSha256": "eadf345d3613ad867788f6a74a8fd1fbba508bb81ec7bc87fe54e4f66dadc69b",
|
||||
"reviewedSourceSha256": "ef8161cc982c9068d3c7eec80f7dd6ef565f05ba0b36bcf58e3b643285b22f0f",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "INTERVIEW_DOCUMENT_FALLBACKS.md; 41 full selected-suite tests, including 12 inherited-name/language cases"
|
||||
},
|
||||
{
|
||||
"inventoryEntryIndex": 138,
|
||||
"file": "job-tracker-ui/src/views/DocumentsPage.tsx",
|
||||
"historicalLine": 243,
|
||||
"expression": "t(({ resume: \"attachmentsPurposeResume\", \"cover-letter\": \"attachmentsPurposeCoverLetter\", portfolio: \"attachmentsPurposePortfolio\", \"case-study\": \"attachmentsPurposeCaseStudy\", certificate: \"attachmentsPurposeCertificate\" } as Record<string, TranslationKey>)[item.purpose.toLowerCase()] ?? \"attachmentsPurposeOther\")",
|
||||
"historicalSourceSha256": "fa53a826ebbdbc868c8b21a0387138c12611d3e2867de0fa0e5f6d8483471eb9",
|
||||
"reviewedSourceSha256": "0b9aaba2c102b4346b10386107b3822016b4f680bb9ab6b58c24ef80b74080fc",
|
||||
"status": "finite-key-domain-reviewed",
|
||||
"runtimeCoverage": "INTERVIEW_DOCUMENT_FALLBACKS.md; 41 full selected-suite tests, including 12 inherited-name/language cases"
|
||||
}
|
||||
],
|
||||
"limitations": [
|
||||
"key-domain review is not full translator context or native-language acceptance",
|
||||
"original inventory is retained as historical evidence",
|
||||
"reviewed hashes must be refreshed after relevant source changes"
|
||||
],
|
||||
"catalogueSha256": "ed99d129f8702181429e10ec02f65f734220409fcba4de51d0d77a0d60871ea4",
|
||||
"hashEncoding": "Reviewed text and inventory hashes use UTF-8 file bytes with CRLF normalized to LF; historicalSourceSha256 retains the original inventory encoding"
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# Error-state translation inputs
|
||||
|
||||
2 November 2026. Twelve historical call sites reviewed through local state constructors; no runtime implementation changed or privileged action executed.
|
||||
|
||||
- ApplicationAssets.tsx:104/887: AssetError.messageKey originates in the private assetError helper with literal/finite conditional arguments, or three explicit cover-AI source error constructors. Conflict status selects revisionConflict; API error text stays display data rather than a catalogue key. Shell is private to this module with AssetError props from these owners.
|
||||
- AdminSystemPage.tsx:333/448/449: ReadKind/ActionKind are bounded by four local read/action entry points; readNotice is called only with status/benchmark/maintenance/email. Error-key maps have fixed entries; success state is supplied only by four local literal runAction calls. API response bodies never supply kind/success keys. No maintenance/probe/email request was run by this review.
|
||||
- CareerProfilePage.tsx:508/509/865: stage/import-label maps already use Object.hasOwn with explicit generic or raw-text fallback. Run action errors are constructed from cancel/retry/accept/discard and conflict status, with fixed key literals; server error message remains data. No import processing or canonical profile mutation was executed.
|
||||
- GmailReviewPage.tsx:231 has two distinct translator calls, both fed by only three literal write-error constructors (save/sync/create). No real mail operation or provider access.
|
||||
- JobDiscoveryPage.tsx:229/230: error state receives only five literal keys from local catches, or null; the first call has a fixed unavailable fallback and the second is guarded by non-null state. No provider request or source grant implied.
|
||||
|
||||
All components obtain t from useI18n. Assertion verified 87 distinct relevant keys, including the import label/stage maps, in both catalogues. This is finite key/owner/control-flow review, not native translation quality, all message formatting or a security/operational pass.
|
||||
|
||||
Register schema 2 now uses immutable inventoryEntryIndex (bound to the original inventory hash) to distinguish the two identical Gmail expressions on the same line. All 74 supplemental indices are unique. Earlier file/line/expression fields remain for readability; they alone cannot identify same-line repeated calls. Reconciliation: 108 original + 74 supplemental = 182 resolved / 6 pending of 188.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Finite owner-map review — 2 November 2026
|
||||
|
||||
Static source review resolves three further historical dynamic call sites; no application code changed.
|
||||
|
||||
| Call | Owner and key bounds | Result |
|
||||
| --- | --- | --- |
|
||||
| CoverLetterDocument.tsx:36, `t(fieldLabels[key])` | `detailFields` is a literal tuple of eight fields; typed fieldLabels maps to letterSenderName/Title/Email/Phone/Location, letterRecipient/Subject/Date; component obtains t from useI18n. | RESOLVED |
|
||||
| CoverLetterDocument.tsx:153, `t(fieldLabels[key])` | `contactFields` is the five-field literal subset; CopyLetterSnapshot obtains t from useI18n. User snapshot values remain interpolated data, never keys. | RESOLVED |
|
||||
| careerCompletenessLabels.ts:15, `t(key)` | Seven literal mapped TranslationKeys: profileCvCompletenessPersonal/Summary/Experience/Education/Skills/Projects/Languages. Unknown labels return verbatim. Both callers, ProfileCompleteness and CareerWorkspaceOverview, pass the useI18n translator. | RESOLVED |
|
||||
|
||||
Graph queries preceded source inspection. A local assertion verified all 15 distinct keys have definitions in both catalogues. This proves finite key coverage and translator ownership, not native translation quality or runtime acceptance. Historical call lines and reviewed source are unchanged by the attachment-title package.
|
||||
|
||||
Reconciliation: 188 historical dynamic calls; 108 previously resolved + 1 checklist category map + 3 here = 112 resolved / 76 pending. The four checklist system-key template calls remain pending. Do not rewrite user-provided contact fields or backend completeness labels merely to translate them.
|
||||
|
||||
Further review resolves CvTemplateGallery.tsx:33's three indexed calls (`labels[0]`, `[1]`, `[2]`). `templateLabels` is a nine-entry Map of typed, fixed three-key tuples; its 27 references contain 24 distinct keys, all asserted present in both catalogues. Calls occur only after a matching tuple was found for Bokmål. Unknown themes and English retain the backend theme metadata as their existing fallback. Gallery and preview-dialog callers obtain language/t from useI18n. Preserve historical theme identities and renderer versions; this review changes neither metadata policy nor rendering. No additional runtime test was required for this source-only review.
|
||||
|
||||
Latest reconciliation: 115 resolved / 73 pending (188 total). The earlier 112/76 count describes the preceding review checkpoint.
|
||||
|
||||
Dashboard follow-through resolves five additional sites: DashboardGrid.tsx:47/63, DashboardLayoutEditor.tsx:77, DashboardView.tsx:372 use the nine literal WIDGETS titleKeys; DashboardView.tsx:259 iterates the three literal table-heading keys. All 12 keys were asserted present in both catalogues; the components use useI18n. WidgetId is derived from WIDGETS; normalizeDashboardLayout discards unknown persisted identifiers and constructs widgets from the matching definition. This establishes the finite translation domain, not arbitrary forged prop safety or layout/device acceptance. Geometry, hidden positions, schema-2 persistence and revisions were not modified.
|
||||
|
||||
Current reconciled total: 120 resolved / 68 pending, still 188 historical dynamic calls. These static reviews do not close the broader every-string context, backend-message or native-language review requirements.
|
||||
|
||||
ApplicationIntelligence.tsx:367/373 review resolves two further sites. timelineCategoryLabel maps five fixed labels, with unknown categories returned as data; matchBandLabel admits only Strong/Partial/Low/Unknown before forming a key and returns unknown bands verbatim. All nine distinct catalogue keys were asserted present in both languages; caller components obtain t from useI18n. Current reconciliation: 122 resolved / 66 pending. This key-domain review does not assert native translation quality or live matching accuracy.
|
||||
|
||||
Follow-up runtime corrections are recorded in UNKNOWN_LABEL_FALLBACKS.md and PIPELINE_ALIAS_FALLBACK.md: inherited property names required own-property guards in the completeness/timeline helpers and pipeline alias normaliser. Their regression evidence supersedes the earlier unconditional static fallback claims. Pipeline's one historical call is now resolved, bringing the intermediate count to 123/65.
|
||||
|
||||
AdminProcessingPage.tsx:153/173/205 adds three source-resolved calls: task filter labels iterate Object.keys(tasks), excluding inherited properties; table headings use six literal keys; detail date labels use four literal tuple keys. useI18n supplies t. Eleven distinct catalogue keys for these domains, plus the ten pipeline label keys, were asserted present in both languages. Backend-derived status/stage/task/event/worker strings remain pending because their dictionary accesses need separate own-property and unknown-value review. Do not count those as covered by the safe literal/own-key iterators.
|
||||
|
||||
Latest reconciliation: 126 resolved / 62 pending, of 188 historical dynamic calls. The chronological counts above are historical checkpoints, not overlapping work to add again.
|
||||
@@ -0,0 +1,7 @@
|
||||
# Import-review and operation label guards
|
||||
|
||||
2 November 2026. Four unchanged sites reviewed: OperationsPage.tsx:127/158 and career/CvImportReview.tsx:114/165. The existing task/status and field/warning dictionaries are all guarded with Object.hasOwn before translation. Unknown task/field/warning text remains data; unknown operation status uses the existing underscore-to-space display fallback. Components obtain t from useI18n. No operation, import, provider, model or profile mutation was executed.
|
||||
|
||||
Every literal dictionary value was checked for definitions in both catalogues. These existing guards prevent inherited-property names from entering the translator; no new implementation was necessary. Source/control-flow review is not native-language, full import accuracy, notification delivery or integrated security acceptance.
|
||||
|
||||
Machine register: 108 original + 78 supplemental = 186 resolved / 2 pending of 188. Remaining sites are interview category and document attachment-purpose lookups; synthetic regressions are in progress, and neither is claimed fixed by this review.
|
||||
@@ -0,0 +1,11 @@
|
||||
# Interview category and document-purpose fallbacks
|
||||
|
||||
2 November 2026. Two confirmed functional defects: inherited Object-property names bypassed interview category raw-text fallback and document-purpose localized Other fallback. Synthetic EN/NB diagnostic run: ten failures, two passing lowercase-purpose controls, 29 unselected cases. This is not a prototype mutation or account-access finding.
|
||||
|
||||
Minimal fixes: Object.hasOwn in the existing interview category helper; a null-prototype object for the existing inline document-purpose map. Exact known labels, purpose lowercasing, existing unknown-value choices and all surrounding workflows remain intact. No role, API, CV/import acceptance, revision, model, provider, storage, database or final UI design changes.
|
||||
|
||||
GREEN: 41 tests across full interview-prep and documents-page suites, zero failures/pending, exit 0. Twelve new cases cover constructor/toString/__proto__ in EN/Bokmål, checking unknown category text and localized Other purpose. Existing cases protect normal interview/follow-up, document filtering/date/link/download and account-safety behavior. Full typecheck and four-file scoped lint passed, zero warnings. Native report: job-tracker-ui/.artifacts/interview-document-fallbacks.json. All 13 dictionary/fallback keys verified in both catalogues. No real model, mail or provider operation.
|
||||
|
||||
Rollback: revert the two lookup changes and twelve test cases; no data conversion or recovery action. Existing labels/history/content are not rewritten. Final integrated security/browser/build qualification remains separately recorded; this test report is not a full application pass.
|
||||
|
||||
The historical 188-call census is now completely accounted for: 108 prior finite-branch sites plus 80 individually reviewed supplemental sites, no overlapping inventory indices, zero pending finite key domains. Register schema 2 distinguishes same-line repeated calls. This does NOT mean complete I18N-00, every-string sensitivity/context, backend-message extraction, plural/select architecture, European locale publication, native translation, accessibility or full runtime coverage is accepted. New code and changed owner dependencies require renewed review. Preserve the original inventory as immutable historical evidence.
|
||||
@@ -0,0 +1,11 @@
|
||||
# Landing and document-index key domains — 2 November 2026
|
||||
|
||||
Eleven additional sites reviewed without source changes. Both pages obtain t from useI18n; no UI/market/document preference or route behavior changed.
|
||||
|
||||
LandingPage.tsx:87/172/173/190/191: FEATURES and STEPS are six-entry literal arrays with fixed title/body keys (24 distinct keys). PUBLIC_PLANS contains Free with five features and Pro with six; the indexed key expression therefore currently yields 11 existing keys. All 35 are defined in both languages. The machine register binds planCatalog.ts as an owner dependency, since adding/reordering features requires renewed key/copy review even if LandingPage itself is unchanged. This resolves key existence, not the accuracy, entitlement, deployment or marketing approval of existing public claims. New public-site content remains separately gated and unpublished.
|
||||
|
||||
DocumentsPage.tsx:222/225/231/264/265 (two expressions at 265): date label is a four-value literal conditional; state/type lookups use finite arrays with explicit fixed-key fallbacks; filter title/option parameters have only three local callers using the literal types/states/visibility arrays. All 22 distinct keys are defined in both catalogues. Unknown state/type objects cannot introduce a catalogue key through array find. Date values, application names and document content remain data. The attachment-purpose inline object lookup at line 243 remains pending; do not assume it has safe arbitrary-key behavior.
|
||||
|
||||
Local assertion checked all 57 distinct keys have definitions in both catalogues, and confirmed actual 5/6 plan feature lengths. No browser or production build rerun for unchanged source-only review. Full native language, plural/formatting, accessibility and feature availability remain separate qualifications.
|
||||
|
||||
Register: 108 originally resolved + 48 individually matched supplemental sites = 156 resolved / 32 pending of 188. Catalogue/source/dependency hashes bind this checkpoint. No call is counted twice.
|
||||
@@ -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.
|
||||
@@ -0,0 +1,13 @@
|
||||
# Processing-monitor translation fallbacks — 2 November 2026
|
||||
|
||||
CONFIRMED functional defect: runtime status/stage/task/event/worker names matching inherited Object properties bypassed existing unknown-value fallbacks. Six EN/Bokmål cases using constructor, toString and __proto__ failed before the fix. No prototype mutation, privilege escalation or backend validation bypass is asserted.
|
||||
|
||||
Minimal shared fix: the five existing label dictionaries now use null-prototype objects, retaining their exact entries and Record typing. All callers, Object.keys filter controls and existing fallback expressions remain intact. No auth/role, API, polling, account-isolation, queue, model or production behavior changed. Known fields translate normally; unknown names reach the existing localized Unknown/Other operation/Unregistered worker/Not recorded labels.
|
||||
|
||||
PASSED: all 17 admin-processing-page tests, zero failures/pending, native exit 0. Six new cases exercise all five map domains, open the collapsed worker-details section, then check timeline event/status/stage fallbacks; eleven existing cases cover normal monitor workflows and safety. An intermediate rerun failed only because the new worker-label visibility assertion inspected a closed details element; the test now opens its summary through the normal UI. That run is not counted as passing or added to the final total.
|
||||
|
||||
PASSED: full typecheck and scoped two-file ESLint, native exits 0. Thirty-eight distinct map/fallback keys asserted present in both catalogues. Local native report: job-tracker-ui/.artifacts/processing-label-fallbacks.json. AST-only graph update required after code edits; keep generated graph separate from the implementation commit. Full build/browser and final integrated security acceptance are not claimed for this patch.
|
||||
|
||||
Five historical call sites resolved: AdminProcessingPage.tsx:130/131/175/191/212. Machine register binds each expression and reviewed source hash: 131 resolved / 57 pending of 188. The earlier safe map iterators retain their coverage with updated source hashes. This is key-domain/fallback evidence, not complete locale or native-language acceptance.
|
||||
|
||||
Rollback: revert the five dictionary constructions and six regression cases; no data migration or restoration needed. Continue remaining owner-map review; preserve unapproved final design and live/security/release gates.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Reminder and interview key review — 2 November 2026
|
||||
|
||||
Five additional historical dynamic call sites resolved by source review; no implementation or runtime inference changed.
|
||||
|
||||
- InterviewPrep.tsx:236/261/285: INTERVIEW_AI_FOCUS is a literal five-entry array. The selected value uses find plus a guaranteed first-entry fallback; menu labels iterate the same array. All five labelKeys are fixed catalogue keys. InterviewAiAssistant obtains t from useI18n. UI language and selected generated-content language remain separate; resolving these labels does not enable AI or prove semantic output quality.
|
||||
- RemindersView.tsx:35/38: generatedReasons is a Map with seven fixed catalogue values; generatedDayReasons has four literal key/regex pairs. Map.get guards the direct lookup; only anchored numeric-day matches interpolate the days placeholder. Unknown reason text returns unchanged as data. The supplied translator is the useI18n translator. Map semantics do not admit inherited Object-property keys.
|
||||
|
||||
All 16 distinct keys were asserted present in both catalogues. This proves finite key coverage and translator ownership, not grammar/native review, all every-string context, plural quality or notification delivery. European plural/formatting architecture remains separately gated; no existing working translation was rewritten. No source edit, live model/provider call, paid scan or duplicate regression rerun was needed for this static review.
|
||||
|
||||
Machine register: 108 original resolved sites + 28 individually recorded supplemental sites = 136 resolved / 52 pending of 188. Source hashes and exact historical expressions are bound in DYNAMIC_RESOLUTION_REGISTER.json. Continue unresolved category/asset/import maps and backend-owned keys; never treat this count as complete i18n acceptance.
|
||||
@@ -0,0 +1,11 @@
|
||||
# Session-change message localisation — 2 November 2026
|
||||
|
||||
Implemented in the existing App invalidation branch. Reuses the existing `sessionChangedCleared` English/Bokmål catalogue message. The canonical document language (`nb-NO`, set by I18nProvider) selects Bokmål; other values safely select English. Reading it occurs only in the invalidated client branch. No provider, hook, storage access, request, dialog or private callback is retained to obtain the message.
|
||||
|
||||
Callers: root App renders Application only while valid; invalidation replaces it with a main alert and preserves the existing passive redirect to /login?sessionChanged=1. I18nProvider already publishes the current UI language to the document; generated-content language is unrelated. All routes, auth/CSRF/context tokens, abort logic and provider teardown remain unchanged. No new translation key or dependency.
|
||||
|
||||
RED: two new root-render tests failed against the previous literal English alert. PASSED after patch: 17 tests in session-boundary-message.test.tsx and session-boundary.test.ts, zero failures/pending, exit 0. New cases verify EN/NB feedback outside the private provider tree and zero API requests. Existing cases exercise cross-tab/cookie invalidation, abort/stale callbacks and session-context handling. These are local Jest/DOM tests; jsdom navigation is not browser redirect qualification.
|
||||
|
||||
PASSED: full TypeScript typecheck; scoped ESLint of App.tsx and the new test, zero warnings. Local ignored native Jest result: job-tracker-ui/.artifacts/session-boundary-message.json. No fresh full build/browser or complete security acceptance claimed. Rollback: revert the two source/test files in this package; no data changes. The attachment-label fix remains independently preserved.
|
||||
|
||||
The original literal-inventory App.tsx entry is now implemented; the inventory remains a historical snapshot. Final integrated security regression must run after relevant application changes are complete.
|
||||
@@ -0,0 +1,15 @@
|
||||
# Unknown translation-map labels — 2 November 2026
|
||||
|
||||
CONFIRMED functional defects, repaired locally with synthetic regressions: Career Profile completeness and application timeline category helpers used ordinary object property lookup. Unknown labels matching inherited Object properties (`constructor`, `toString`, `__proto__`) were incorrectly sent to the translator, losing the original text and producing missing visible/accessible labels. This is not a prototype-pollution or account-access finding; no such impact is claimed.
|
||||
|
||||
Minimal fix: Object.hasOwn guards in the two existing helpers. Known keys still translate normally, other strings remain data. Callers: ProfileCompleteness and CareerWorkspaceOverview; ApplicationTimeline. No API, persisted profile/category, UI language preference, generated-content language or revision behavior changes; no dependencies added.
|
||||
|
||||
RED: three inherited-name Career Profile cases failed (two known/custom control cases passed); three timeline-category cases failed before the patch (11 unselected cases were skipped in that diagnostic run). GREEN final combined execution: 41 tests across four suites, zero failures/pending, native exit 0: career-completeness-labels, career-history-view, career-workspace-page and application-intelligence. Do not add the overlapping earlier 27-case run to this total. Full typecheck and scoped four-file ESLint passed, zero warnings.
|
||||
|
||||
Native ignored JSON: job-tracker-ui/.artifacts/translation-map-fallbacks.json. Known-key test checks the translated catalogue key; timeline tests verify accessible button names for all three inherited-name canaries. No production or live provider/model used. Full integrated security testing remains deferred until relevant application changes are complete.
|
||||
|
||||
Correction to earlier static review: finite literal-key coverage alone did not prove the stated unknown-label fallback for these ordinary object maps. These regressions now verify it. The checklist category helper's current caller iterates CHECKLIST_CATEGORIES, so arbitrary unknown categories never reach its lookup; no speculative checklist change was made. Other maps with external keys, including processing-monitor maps, still need equivalent reachability/fallback review. Dynamic-call total remains 122 resolved / 66 pending; this remediation is not another resolved call count.
|
||||
|
||||
Rollback: revert the two helper lines and associated tests only; no data rollback needed. Remaining limits: no claim of native-language quality, full WCAG, all map coverage or final integrated security acceptance.
|
||||
|
||||
Final build: Next.js 16.4.1 static production build PASSED, exit 0, including TypeScript and all three generated pages. This also builds the session-message and preceding attachment-label fixes on this branch. API build-time base was local; no deployment or live service validation. Sanitized native reports are retained in evidence/translation-map-fallbacks.json.gz and evidence/session-boundary-message.json.gz (41 and 17 disjoint selected tests respectively).
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -29,6 +29,7 @@ import JobTable from "./components/JobTable";
|
||||
import NotificationsPopover from "./components/NotificationsPopover";
|
||||
import type { JobTableColumns } from "./components/JobTable";
|
||||
import { I18nProvider, useI18n } from "./i18n/I18nProvider";
|
||||
import { translations } from "./i18n/translations";
|
||||
import LoginPage from "./views/LoginPage";
|
||||
import LandingPage from "./views/LandingPage";
|
||||
import ForgotPasswordPage from "./views/ForgotPasswordPage";
|
||||
@@ -485,7 +486,7 @@ export default function App() {
|
||||
}, [invalidated]);
|
||||
// Unmount providers as well as routes: confirmations/toasts can retain private text and
|
||||
// callbacks. Passive effect navigation runs after the old forms' unload guards are removed.
|
||||
return invalidated ? <main role="alert">Session changed. Clearing this page…</main> : <Application />;
|
||||
return invalidated ? <main role="alert">{translations[document.documentElement.lang === "nb-NO" ? "nb" : "en"].sessionChangedCleared}</main> : <Application />;
|
||||
}
|
||||
|
||||
function Application() {
|
||||
|
||||
@@ -20,6 +20,32 @@ beforeEach(() => {
|
||||
});
|
||||
afterEach(() => jest.useRealTimers());
|
||||
|
||||
test.each([
|
||||
['en', 'constructor', 'Other operation', 'Unknown', 'Unregistered worker', 'Not recorded'],
|
||||
['en', 'toString', 'Other operation', 'Unknown', 'Unregistered worker', 'Not recorded'],
|
||||
['en', '__proto__', 'Other operation', 'Unknown', 'Unregistered worker', 'Not recorded'],
|
||||
['nb', 'constructor', 'Annen oppgave', 'Ukjent', 'Uregistrert bakgrunnsprosess', 'Ikke registrert'],
|
||||
['nb', 'toString', 'Annen oppgave', 'Ukjent', 'Uregistrert bakgrunnsprosess', 'Ikke registrert'],
|
||||
['nb', '__proto__', 'Annen oppgave', 'Ukjent', 'Uregistrert bakgrunnsprosess', 'Ikke registrert'],
|
||||
])('uses safe %s fallbacks for inherited processing key %s', async (language, key, other, unknown, unregistered, notRecorded) => {
|
||||
localStorage.setItem('uiLanguage', language);
|
||||
const unknownItem = { ...item, taskType: key, status: key, stage: key };
|
||||
get.mockImplementation((url: string) => Promise.resolve({ data: url.includes('/events')
|
||||
? { items: [{ id: '1', kind: key, status: key, stage: key, attempt: 1, failureCode: null, atUtc: item.createdAtUtc }], hasMore: false, retentionDays: 30 }
|
||||
: url.includes(item.id) ? unknownItem
|
||||
: { ...listing, items: [unknownItem], counts: { [key]: 1 }, workers: [{ ...listing.workers[0], name: key }] } }));
|
||||
open();
|
||||
const details = await screen.findByText(other, { selector: 'button' });
|
||||
expect(screen.getByText(`${unknown}: 1`)).toBeVisible();
|
||||
const workerLabel = screen.getByText(new RegExp(`^${unregistered}:`));
|
||||
fireEvent.click(workerLabel.closest('details')!.querySelector('summary')!);
|
||||
expect(workerLabel).toBeVisible();
|
||||
fireEvent.click(details);
|
||||
const events = await screen.findByRole('list');
|
||||
expect(events).toHaveTextContent(`${unknown} · ${unknown}`);
|
||||
expect(events).toHaveTextContent(notRecorded);
|
||||
});
|
||||
|
||||
test('shows safe job metadata and real events with a copyable correlation ID', async () => {
|
||||
open();
|
||||
expect(await screen.findByText('Synthetic owner')).toBeVisible();
|
||||
|
||||
@@ -68,6 +68,14 @@ test("localizes system checklist content without changing user-authored tasks",
|
||||
expect(screen.getByText("Ask Sara for a referral")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test.each(['en', 'nb'])('preserves unknown historical system task text in %s', async language => {
|
||||
window.localStorage.setItem('uiLanguage', language);
|
||||
mockedApi.get.mockResolvedValue({ data: checklist([item({ systemKey: 'retired-system-task', title: 'Reviewed historical task', description: 'Original task details' })]) } as any);
|
||||
renderChecklist();
|
||||
expect(await screen.findByText('Reviewed historical task')).toBeInTheDocument();
|
||||
expect(screen.getByText('Original task details')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("renders the checklist grouped by category with progress", async () => {
|
||||
renderChecklist();
|
||||
|
||||
|
||||
@@ -78,6 +78,12 @@ const match = {
|
||||
|
||||
beforeEach(() => jest.clearAllMocks());
|
||||
|
||||
test.each(["constructor", "toString", "__proto__"])("timeline preserves unknown category %s as a label", async category => {
|
||||
mockedApi.get.mockResolvedValue({ data: { ...timeline, categories: ["stage", category] } } as any);
|
||||
render(<ApplicationTimeline jobId={7} />);
|
||||
expect(await screen.findByRole("button", { name: category })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// ---------- Timeline ----------
|
||||
|
||||
test("timeline renders grouped days, milestones and readable summaries", async () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { api } from "./api";
|
||||
import { translations } from "./i18n/translations";
|
||||
|
||||
// Mirrors WorkspaceOverviewDto. Read-only aggregate — the workspace owns no data.
|
||||
export type WorkspaceCv = {
|
||||
@@ -93,7 +94,9 @@ export const WORKSPACE_SECTIONS: { key: WorkspaceSectionKey; label: string }[] =
|
||||
|
||||
export function checklistSystemTranslationToken(systemKey?: string | null): string | null {
|
||||
if (!systemKey || systemKey.startsWith("learning:")) return null;
|
||||
return systemKey.replace(/-([a-z])/g, (_, letter: string) => letter.toUpperCase());
|
||||
const token = systemKey.replace(/-([a-z])/g, (_, letter: string) => letter.toUpperCase());
|
||||
return Object.hasOwn(translations.en, `checklistItem_${token}`)
|
||||
&& Object.hasOwn(translations.en, `checklistItem_${token}Description`) ? token : null;
|
||||
}
|
||||
|
||||
const LEGACY_WORKSPACE_SECTIONS: Record<string, WorkspaceSectionKey> = {
|
||||
|
||||
@@ -22,6 +22,33 @@ const mockedApi = api as jest.Mocked<typeof api>;
|
||||
|
||||
beforeEach(() => jest.clearAllMocks());
|
||||
|
||||
test.each([
|
||||
['en', 'Preview: resume.pdf', 'Preview: resume.pdf'],
|
||||
['nb', 'Forhåndsvis: resume.pdf', 'Forhåndsvisning: resume.pdf'],
|
||||
])('PDF preview identifies the document in %s', async (language, buttonName, frameTitle) => {
|
||||
const previousLanguage = localStorage.getItem('uiLanguage');
|
||||
const originalCreate = URL.createObjectURL;
|
||||
const originalRevoke = URL.revokeObjectURL;
|
||||
localStorage.setItem('uiLanguage', language);
|
||||
URL.createObjectURL = jest.fn(() => 'blob:attachment-preview');
|
||||
URL.revokeObjectURL = jest.fn();
|
||||
mockedApi.get.mockResolvedValueOnce({ data: [{ id: 7, fileName: 'resume.pdf', fileType: 'application/pdf', fileSize: 2048, uploadDate: '2026-11-02T10:00:00Z' }] } as any);
|
||||
mockedApi.get.mockResolvedValueOnce({ data: new Blob(['sample'], { type: 'application/pdf' }) } as any);
|
||||
const view = render(<ToastProvider><I18nProvider><ConfirmProvider><PromptProvider><Attachments jobId={42} /></PromptProvider></ConfirmProvider></I18nProvider></ToastProvider>);
|
||||
try {
|
||||
fireEvent.click(await screen.findByRole('button', { name: buttonName }));
|
||||
const frame = await screen.findByTitle(frameTitle);
|
||||
expect(frame.tagName).toBe('IFRAME');
|
||||
expect(frame).toHaveAttribute('src', 'blob:attachment-preview');
|
||||
} finally {
|
||||
view.unmount();
|
||||
URL.createObjectURL = originalCreate;
|
||||
URL.revokeObjectURL = originalRevoke;
|
||||
if (previousLanguage === null) localStorage.removeItem('uiLanguage');
|
||||
else localStorage.setItem('uiLanguage', previousLanguage);
|
||||
}
|
||||
});
|
||||
|
||||
test('attachments empty state renders drag and drop guidance', async () => {
|
||||
mockedApi.get.mockResolvedValueOnce({ data: [] } as any);
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { localizeCompletenessLabel } from "./views/career/careerCompletenessLabels";
|
||||
|
||||
test.each(["constructor", "toString", "__proto__", "Custom section"])("preserves unknown completeness label %s as data", label => {
|
||||
const translate = jest.fn(() => "translated");
|
||||
expect(localizeCompletenessLabel(label, translate)).toBe(label);
|
||||
expect(translate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("translates a known completeness label using its catalogue key", () => {
|
||||
const translate = jest.fn(() => "Personopplysninger");
|
||||
expect(localizeCompletenessLabel("Personal details", translate)).toBe("Personopplysninger");
|
||||
expect(translate).toHaveBeenCalledWith("profileCvCompletenessPersonal");
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { checklistSystemTranslationToken } from './applicationWorkspace';
|
||||
|
||||
test.each(['retired-system-task', 'constructor', '__proto__'])('does not manufacture translation keys for %s', key => {
|
||||
expect(checklistSystemTranslationToken(key)).toBeNull();
|
||||
});
|
||||
|
||||
test('retains the known system translation and learning/custom boundaries', () => {
|
||||
expect(checklistSystemTranslationToken('prepare-cv')).toBe('prepareCv');
|
||||
expect(checklistSystemTranslationToken('learning:prepare-cv')).toBeNull();
|
||||
expect(checklistSystemTranslationToken(null)).toBeNull();
|
||||
});
|
||||
@@ -364,7 +364,7 @@ function timelineCategoryLabel(t: (key: any) => string, category: string): strin
|
||||
communication: "intelligenceCategoryCommunication",
|
||||
ai: "intelligenceCategoryAi",
|
||||
};
|
||||
return keys[category] ? t(keys[category]) : category;
|
||||
return Object.hasOwn(keys, category) ? t(keys[category]) : category;
|
||||
}
|
||||
|
||||
function matchBandLabel(t: (key: any) => string, band?: string): string {
|
||||
|
||||
@@ -358,7 +358,7 @@ export default function Attachments({ jobId }: { jobId: number }) {
|
||||
<img src={preview.url} alt={preview.name} style={{ maxWidth: "100%", maxHeight: "70vh", borderRadius: 12 }} />
|
||||
</Box>
|
||||
) : isPdfType(preview.type) ? (
|
||||
<iframe title="pdf" src={preview.url} style={{ width: "100%", height: 560, border: 0, borderRadius: 12 }} />
|
||||
<iframe title={t("attachmentsPreviewTitle", { name: preview.name })} src={preview.url} style={{ width: "100%", height: 560, border: 0, borderRadius: 12 }} />
|
||||
) : (
|
||||
<Typography sx={{ color: "text.secondary" }}>{t("attachmentsNoInlinePreview")}</Typography>
|
||||
)}
|
||||
|
||||
@@ -502,5 +502,5 @@ function interviewCategoryLabel(t: (key: any) => string, category: string) {
|
||||
note: "interviewCategoryNotes",
|
||||
debrief: "interviewCategoryDebrief",
|
||||
};
|
||||
return keys[category] ? t(keys[category]) : category;
|
||||
return Object.hasOwn(keys, category) ? t(keys[category]) : category;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,15 @@ function page(items: ReturnType<typeof item>[] = [item()], currentPage = 1, tota
|
||||
return { items, page: currentPage, pageSize: 25, total, totalPages: Math.ceil(total / 25) };
|
||||
}
|
||||
|
||||
describe.each(['en', 'nb'])('%s unknown attachment purposes', language => {
|
||||
test.each(['constructor', 'toString', '__proto__'])('uses the localized Other label for %s', async purpose => {
|
||||
localStorage.setItem('uiLanguage', language);
|
||||
mockedApi.get.mockResolvedValue({ data: page([item({ type: 'attachment', purpose, visibility: 'private' })]) } as never);
|
||||
renderPage();
|
||||
expect(await screen.findByText(`${copy('attachmentsPurpose')}: ${copy('attachmentsPurposeOther')}`)).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
function deferred<T>() {
|
||||
let resolve!: (value: T) => void;
|
||||
let reject!: (reason: unknown) => void;
|
||||
|
||||
@@ -62,6 +62,16 @@ beforeEach(() => {
|
||||
window.localStorage.setItem("uiLanguage", "en");
|
||||
});
|
||||
|
||||
describe.each(['en', 'nb'])('%s unknown interview categories', language => {
|
||||
test.each(['constructor', 'toString', '__proto__'])('preserves %s as a category label', async category => {
|
||||
window.localStorage.setItem('uiLanguage', language);
|
||||
routeGet({ board: { ...board, groups: [{ ...board.groups[0], category }] } });
|
||||
render(<ApplicationInterviewPrep jobId={7} />);
|
||||
expect(await screen.findByText(category)).toBeInTheDocument();
|
||||
expect(screen.getByText('Funding history')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
test("localizes interview categories while preserving user-authored preparation", async () => {
|
||||
window.localStorage.setItem("uiLanguage", "nb");
|
||||
routeGet();
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom";
|
||||
import App from "./App";
|
||||
import { I18nProvider } from "./i18n/I18nProvider";
|
||||
import { api } from "./api";
|
||||
|
||||
jest.mock("./sessionBoundary", () => ({
|
||||
isSessionInvalidated: () => true,
|
||||
SESSION_INVALIDATED_EVENT: "session-invalidated",
|
||||
}));
|
||||
jest.mock("./i18n/I18nProvider", () => ({
|
||||
...jest.requireActual("./i18n/I18nProvider"),
|
||||
I18nProvider: jest.fn(() => { throw new Error("Invalidated sessions must not mount providers"); }),
|
||||
}));
|
||||
|
||||
test.each([
|
||||
["en", "Your session changed. Private data and unsaved edits were cleared from this page. Sign in again to continue."],
|
||||
["nb-NO", "Økten din ble endret. Private data og ulagrede endringer ble fjernet fra denne siden. Logg inn igjen for å fortsette."],
|
||||
])("invalidated session shows %s feedback outside the private provider tree", (language, message) => {
|
||||
const previousLanguage = document.documentElement.lang;
|
||||
document.documentElement.lang = language;
|
||||
try {
|
||||
render(<App />);
|
||||
expect(screen.getByRole("alert")).toHaveTextContent(message);
|
||||
expect(I18nProvider).not.toHaveBeenCalled();
|
||||
expect(api.get).not.toHaveBeenCalled();
|
||||
} finally {
|
||||
document.documentElement.lang = previousLanguage;
|
||||
}
|
||||
});
|
||||
@@ -19,11 +19,11 @@ type Item = {
|
||||
type Listing = { items: Item[]; total: number; counts: Record<string, number>; workers: { name: string; flagEnabled: boolean; individualOperationsRecorded: boolean }[] };
|
||||
type Event = { id: string; atUtc: string; kind: string; status: string; stage: string | null; attempt: number; failureCode: string | null };
|
||||
type Events = { items: Event[]; hasMore: boolean; retentionDays: number };
|
||||
const statuses: Record<string, TranslationKey> = { queued: 'operationsStatusQueued', running: 'operationsStatusRunning', waiting_for_retry: 'operationsStatusWaitingForRetry', waiting_for_external_fallback: 'operationsStatusWaitingForFallback', succeeded: 'operationsStatusSucceeded', failed: 'operationsStatusFailed', cancelled: 'operationsStatusCancelled' };
|
||||
const tasks: Record<string, TranslationKey> = { 'cv.process': 'operationsTaskCv', 'strategy.snapshot': 'operationsTaskStrategy' };
|
||||
const stages: Record<string, TranslationKey> = { cv_validating_file: 'cvImportStageValidating', cv_extracting: 'cvImportStageExtracting', cv_identifying_sections: 'cvImportStageSections', cv_analysing: 'cvImportStageAnalysing', cv_validating_details: 'cvImportStageDetails', cv_preparing_review: 'cvImportStagePreparing', cv_review_ready: 'cvImportStageReady' };
|
||||
const kinds: Record<string, TranslationKey> = { Created: 'processingEventCreated', Claimed: 'processingEventClaimed', StageChanged: 'processingEventStageChanged', Completed: 'processingEventCompleted', RetryScheduled: 'processingEventRetryScheduled', Failed: 'processingEventFailed', CancellationRequested: 'processingEventCancellationRequested', Cancelled: 'processingEventCancelled', Retried: 'processingEventRetried', LeaseRecovered: 'processingEventLeaseRecovered', Expired: 'processingEventExpired' };
|
||||
const workers: Record<string, TranslationKey> = { AiOperations: 'processingWorkerAi', CvDocumentImports: 'processingWorkerDocument', JobEnrichment: 'processingWorkerEnrichment', Rules: 'processingWorkerRules', FollowUpReminders: 'processingWorkerReminders', DailyExport: 'processingWorkerExport', SavedJobSearchAlerts: 'processingWorkerSearch' };
|
||||
const statuses: Record<string, TranslationKey> = Object.assign(Object.create(null), { queued: 'operationsStatusQueued', running: 'operationsStatusRunning', waiting_for_retry: 'operationsStatusWaitingForRetry', waiting_for_external_fallback: 'operationsStatusWaitingForFallback', succeeded: 'operationsStatusSucceeded', failed: 'operationsStatusFailed', cancelled: 'operationsStatusCancelled' });
|
||||
const tasks: Record<string, TranslationKey> = Object.assign(Object.create(null), { 'cv.process': 'operationsTaskCv', 'strategy.snapshot': 'operationsTaskStrategy' });
|
||||
const stages: Record<string, TranslationKey> = Object.assign(Object.create(null), { cv_validating_file: 'cvImportStageValidating', cv_extracting: 'cvImportStageExtracting', cv_identifying_sections: 'cvImportStageSections', cv_analysing: 'cvImportStageAnalysing', cv_validating_details: 'cvImportStageDetails', cv_preparing_review: 'cvImportStagePreparing', cv_review_ready: 'cvImportStageReady' });
|
||||
const kinds: Record<string, TranslationKey> = Object.assign(Object.create(null), { Created: 'processingEventCreated', Claimed: 'processingEventClaimed', StageChanged: 'processingEventStageChanged', Completed: 'processingEventCompleted', RetryScheduled: 'processingEventRetryScheduled', Failed: 'processingEventFailed', CancellationRequested: 'processingEventCancellationRequested', Cancelled: 'processingEventCancelled', Retried: 'processingEventRetried', LeaseRecovered: 'processingEventLeaseRecovered', Expired: 'processingEventExpired' });
|
||||
const workers: Record<string, TranslationKey> = Object.assign(Object.create(null), { AiOperations: 'processingWorkerAi', CvDocumentImports: 'processingWorkerDocument', JobEnrichment: 'processingWorkerEnrichment', Rules: 'processingWorkerRules', FollowUpReminders: 'processingWorkerReminders', DailyExport: 'processingWorkerExport', SavedJobSearchAlerts: 'processingWorkerSearch' });
|
||||
const failureCodes = ['timeout', 'lease_expired', 'deadline_exceeded', 'entitlement_changed', 'document_unavailable', 'sidecar_unavailable', 'upstream_unavailable', 'invalid_response', 'circuit_open', 'rate_limited', 'permission_denied', 'cancelled', 'upload_rejected', 'parser_failed', 'malformed_output', 'provider_unavailable', 'processing_failed'];
|
||||
|
||||
export default function AdminProcessingPage() {
|
||||
|
||||
@@ -240,7 +240,7 @@ export default function DocumentsPage() {
|
||||
{item.type === "email-draft" ? <Typography variant="caption" color="text.secondary">{t("documentsEmailHelp")}</Typography> : null}
|
||||
{item.type === "attachment" ? <>
|
||||
<Typography variant="caption" color="text.secondary">{[item.fileType, item.fileSize != null ? t("documentsFileSize", { size: new Intl.NumberFormat(locale, { maximumFractionDigits: 1 }).format(item.fileSize / 1024) }) : null].filter(Boolean).join(" · ")}</Typography>
|
||||
{item.purpose ? <Typography variant="caption" color="text.secondary">{t("attachmentsPurpose")}: {t(({ resume: "attachmentsPurposeResume", "cover-letter": "attachmentsPurposeCoverLetter", portfolio: "attachmentsPurposePortfolio", "case-study": "attachmentsPurposeCaseStudy", certificate: "attachmentsPurposeCertificate" } as Record<string, TranslationKey>)[item.purpose.toLowerCase()] ?? "attachmentsPurposeOther")}</Typography> : null}
|
||||
{item.purpose ? <Typography variant="caption" color="text.secondary">{t("attachmentsPurpose")}: {t((Object.assign(Object.create(null), { resume: "attachmentsPurposeResume", "cover-letter": "attachmentsPurposeCoverLetter", portfolio: "attachmentsPurposePortfolio", "case-study": "attachmentsPurposeCaseStudy", certificate: "attachmentsPurposeCertificate" }) as Record<string, TranslationKey>)[item.purpose.toLowerCase()] ?? "attachmentsPurposeOther")}</Typography> : null}
|
||||
{item.purpose?.toLowerCase() === "certificate" ? <Typography variant="caption" color="text.secondary">{t("documentsCertificateHelp")}</Typography> : null}
|
||||
{item.useForAi != null ? <Typography variant="caption" color="text.secondary">{t("attachmentsAiUse")}: {t(item.useForAi ? "attachmentsAiEnabled" : "attachmentsAiDisabled")}</Typography> : null}
|
||||
</> : null}
|
||||
|
||||
@@ -11,6 +11,6 @@ const completenessLabelKeys: Record<string, TranslationKey> = {
|
||||
};
|
||||
|
||||
export function localizeCompletenessLabel(label: string, t: (key: TranslationKey) => string) {
|
||||
const key = completenessLabelKeys[label];
|
||||
const key = Object.hasOwn(completenessLabelKeys, label) ? completenessLabelKeys[label] : undefined;
|
||||
return key ? t(key) : label;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user