diff --git a/.github/scripts/tests/test_command_descriptions.py b/.github/scripts/tests/test_command_descriptions.py
index 8e48a44d..93186be9 100644
--- a/.github/scripts/tests/test_command_descriptions.py
+++ b/.github/scripts/tests/test_command_descriptions.py
@@ -217,6 +217,10 @@ class CommandDescriptionsTests(unittest.TestCase):
"reasonStoppedContainer",
english["vmLxc"]["scheduled"]["reasonStoppedContainer"],
)
+ messages["vmLxc"]["scheduled"].setdefault(
+ "reasonStoppedContainerHistorical",
+ english["vmLxc"]["scheduled"]["reasonStoppedContainerHistorical"],
+ )
messages["vmLxc"]["scheduled"].setdefault(
"runSkippedStatus",
english["vmLxc"]["scheduled"]["runSkippedStatus"],
diff --git a/AppImage/components/virtual-machines.tsx b/AppImage/components/virtual-machines.tsx
index a571c426..901655d4 100644
--- a/AppImage/components/virtual-machines.tsx
+++ b/AppImage/components/virtual-machines.tsx
@@ -2450,7 +2450,9 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
if (!scheduleLastRunAt || !selectedVM) return null
const spacing = indented ? "pl-4" : ""
const scheduleLastRunReasonText = scheduleLastRunReasonCode === "stopped_container"
- ? t("vmLxc.scheduled.reasonStoppedContainer")
+ ? selectedVM.status === "stopped"
+ ? t("vmLxc.scheduled.reasonStoppedContainer")
+ : t("vmLxc.scheduled.reasonStoppedContainerHistorical")
: scheduleLastRunReason
return (
diff --git a/AppImage/messages/en/common.json b/AppImage/messages/en/common.json
index 55b5b4b9..832f5c77 100644
--- a/AppImage/messages/en/common.json
+++ b/AppImage/messages/en/common.json
@@ -1289,7 +1289,8 @@
"runDeferred": "held for safety",
"runSkipped": "nothing pending",
"runSkippedStatus": "run skipped",
- "reasonStoppedContainer": "Container was stopped; scheduled update was skipped.",
+ "reasonStoppedContainer": "Container is stopped; scheduled update was skipped.",
+ "reasonStoppedContainerHistorical": "Container was stopped when the scheduled update was due to run.",
"releaseDelaySummary": "{days}-day release hold",
"releaseDelayLabel": "Wait after a new app release",
"releaseDelayNone": "No waiting period",
diff --git a/AppImage/messages/sk/common.json b/AppImage/messages/sk/common.json
index 2297cb21..cd290e08 100644
--- a/AppImage/messages/sk/common.json
+++ b/AppImage/messages/sk/common.json
@@ -1289,7 +1289,8 @@
"runDeferred": "odložené z bezpečnostných dôvodov",
"runSkipped": "nič nečaká",
"runSkippedStatus": "spustenie bolo preskočené",
- "reasonStoppedContainer": "Kontajner bol vypnutý; plánovaná aktualizácia sa preskočila.",
+ "reasonStoppedContainer": "Kontajner je vypnutý; plánovaná aktualizácia sa preskočila.",
+ "reasonStoppedContainerHistorical": "Kontajner bol vypnutý, keď sa mala spustiť plánovaná aktualizácia.",
"releaseDelaySummary": "odklad {days} deň/dní",
"releaseDelayLabel": "Počkať po novej verzii aplikácie",
"releaseDelayNone": "Bez čakacej doby",
diff --git a/tests/lxc_updates/test_scheduled_reason_i18n.cjs b/tests/lxc_updates/test_scheduled_reason_i18n.cjs
index a87e7354..c03f4c8c 100644
--- a/tests/lxc_updates/test_scheduled_reason_i18n.cjs
+++ b/tests/lxc_updates/test_scheduled_reason_i18n.cjs
@@ -63,7 +63,7 @@ for (const locale of ['en', 'sk']) {
return String(message ?? key).replace(/\{([^}]+)\}/g, (_, name) => String(variables[name] ?? `{${name}}`))
}
const context = {
- exports: {}, t, selectedVM: { vmid: 100 }, scheduleLastRunAt: '2026-10-16T05:10:02Z',
+ exports: {}, t, selectedVM: { vmid: 100, status: 'stopped' }, scheduleLastRunAt: '2026-10-16T05:10:02Z',
scheduleLastRunStatus: 'skipped', scheduleLastRunReasonCode: 'stopped_container',
scheduleLastRunReason: 'container is stopped; scheduled update was skipped',
scheduleLastRunRebootRequired: false, scheduleLastRunRebootPackages: [], scheduleLastRunLog: null,
@@ -72,17 +72,29 @@ for (const locale of ['en', 'sk']) {
}
const render = compile(context)
const translated = flattenText(render(true))
- const expected = t('vmLxc.scheduled.reasonStoppedContainer')
+ const expectedCurrentReason = t('vmLxc.scheduled.reasonStoppedContainer')
+ const expectedHistoricalReason = t('vmLxc.scheduled.reasonStoppedContainerHistorical')
const skippedLabel = t('vmLxc.scheduled.runSkippedStatus')
- const expectedHistoricalReason = locale === 'sk'
- ? 'Kontajner bol vypnutý; plánovaná aktualizácia sa preskočila.'
- : 'Container was stopped; scheduled update was skipped.'
- assert.equal(expected, expectedHistoricalReason,
- `${locale}: stopped reason must describe the historical scheduled run, not current container state`)
- assert(translated.includes(expected), `${locale}: known reason code must use the locale catalog`)
+ const expectedCurrentText = locale === 'sk'
+ ? 'Kontajner je vypnutý; plánovaná aktualizácia sa preskočila.'
+ : 'Container is stopped; scheduled update was skipped.'
+ const expectedHistoricalText = locale === 'sk'
+ ? 'Kontajner bol vypnutý, keď sa mala spustiť plánovaná aktualizácia.'
+ : 'Container was stopped when the scheduled update was due to run.'
+ assert.equal(expectedCurrentReason, expectedCurrentText,
+ `${locale}: stopped CT must describe its current stopped state`)
+ assert.equal(expectedHistoricalReason, expectedHistoricalText,
+ `${locale}: running CT must describe the stopped state at the prior scheduled run`)
+ assert(translated.includes(expectedCurrentReason), `${locale}: currently stopped CT must use the present-state catalog`)
+ assert(!translated.includes(expectedHistoricalReason), `${locale}: currently stopped CT must not use historical wording`)
assert(translated.includes(skippedLabel), `${locale}: skipped run must not claim that no updates are pending`)
assert(!translated.includes(context.scheduleLastRunReason), `${locale}: raw stopped reason must not leak into UI`)
+ context.selectedVM.status = 'running'
+ const historical = flattenText(render(true))
+ assert(historical.includes(expectedHistoricalReason), `${locale}: running CT must use historical wording for a past skipped run`)
+ assert(!historical.includes(expectedCurrentReason), `${locale}: running CT must not claim it is currently stopped`)
+
context.scheduleLastRunReasonCode = 'unknown_reason'
const fallback = flattenText(render(true))
assert(fallback.includes(context.scheduleLastRunReason), `${locale}: unknown code must retain the raw diagnostic`)