R3.2.8.6-R1.3C-KK1-R6A Final-Gate Self-Cancellation and Four-Language Theme Contrast Fix

#36
.streamlit/desktop.ini DELETED
@@ -1,2 +0,0 @@
1
- [.ShellClassInfo]
2
- IconResource=C:\Program Files\Google\Drive File Stream\129.0.1.0\GoogleDriveFS.exe,27
 
 
 
app.py CHANGED
@@ -844,8 +844,8 @@ def _render_checkpoint_preview(task: dict, lang_code: str) -> None:
844
  st.markdown(tr(lang_code, "english_draft"))
845
  st.markdown(
846
  f"""
847
- <div id='sp-live-manuscript-shell' style='border:1px solid #e5e7eb;border-radius:8px;padding:14px 16px;min-height:220px;max-height:68vh;overflow:auto;background:#ffffff;'>
848
- <div id='sp-live-manuscript-status' style='white-space:pre-wrap;font-size:0.88em;opacity:0.72;margin:0 0 8px 0;display:{english_status_display};'>{html.escape(english_status_initial)}</div>
849
  <div id='sp-live-manuscript-preview' data-sp-placeholder='{english_placeholder}' style='white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-family:inherit;line-height:1.72;color:#111827;'>{html.escape(english_initial)}</div>
850
  <span id='sp-live-manuscript-cursor' aria-hidden='true' style='display:inline-block;width:7px;height:1.05em;background:#111827;margin-left:2px;vertical-align:-0.12em;animation:spBlink 1s steps(1,end) infinite;'></span>
851
  </div>
@@ -856,7 +856,7 @@ def _render_checkpoint_preview(task: dict, lang_code: str) -> None:
856
  st.markdown(tr(lang_code, "target_draft", flag=get_target_flag(lang_code)))
857
  st.markdown(
858
  f"""
859
- <div id='sp-live-translation-shell' style='border:1px solid #e5e7eb;border-radius:8px;padding:14px 16px;min-height:220px;max-height:68vh;overflow:auto;background:#ffffff;'>
860
  <div id='sp-live-translation-preview' data-sp-placeholder='{target_placeholder}' style='white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-family:inherit;line-height:1.72;color:#111827;'>{html.escape(target_initial)}</div>
861
  <span id='sp-live-translation-cursor' aria-hidden='true' style='display:inline-block;width:7px;height:1.05em;background:#111827;margin-left:2px;vertical-align:-0.12em;animation:spBlink 1s steps(1,end) infinite;'></span>
862
  </div>
 
844
  st.markdown(tr(lang_code, "english_draft"))
845
  st.markdown(
846
  f"""
847
+ <div id='sp-live-manuscript-shell' style='border:1px solid #e5e7eb;border-radius:8px;padding:14px 16px;min-height:220px;max-height:68vh;overflow:auto;background:#ffffff;color:#111827;'>
848
+ <div id='sp-live-manuscript-status' style='white-space:pre-wrap;font-size:0.88em;color:#374151;opacity:1;margin:0 0 8px 0;display:{english_status_display};'>{html.escape(english_status_initial)}</div>
849
  <div id='sp-live-manuscript-preview' data-sp-placeholder='{english_placeholder}' style='white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-family:inherit;line-height:1.72;color:#111827;'>{html.escape(english_initial)}</div>
850
  <span id='sp-live-manuscript-cursor' aria-hidden='true' style='display:inline-block;width:7px;height:1.05em;background:#111827;margin-left:2px;vertical-align:-0.12em;animation:spBlink 1s steps(1,end) infinite;'></span>
851
  </div>
 
856
  st.markdown(tr(lang_code, "target_draft", flag=get_target_flag(lang_code)))
857
  st.markdown(
858
  f"""
859
+ <div id='sp-live-translation-shell' style='border:1px solid #e5e7eb;border-radius:8px;padding:14px 16px;min-height:220px;max-height:68vh;overflow:auto;background:#ffffff;color:#111827;'>
860
  <div id='sp-live-translation-preview' data-sp-placeholder='{target_placeholder}' style='white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-family:inherit;line-height:1.72;color:#111827;'>{html.escape(target_initial)}</div>
861
  <span id='sp-live-translation-cursor' aria-hidden='true' style='display:inline-block;width:7px;height:1.05em;background:#111827;margin-left:2px;vertical-align:-0.12em;animation:spBlink 1s steps(1,end) infinite;'></span>
862
  </div>
core/desktop.ini DELETED
@@ -1,2 +0,0 @@
1
- [.ShellClassInfo]
2
- IconResource=C:\Program Files\Google\Drive File Stream\129.0.1.0\GoogleDriveFS.exe,27
 
 
 
core/generation_runner.py CHANGED
@@ -70,6 +70,10 @@ class _OrderedTranslationWorker:
70
  self._handler = handler
71
  self._queue = queue.Queue()
72
  self._stop = threading.Event()
 
 
 
 
73
  self._thread = threading.Thread(
74
  target=self._run,
75
  name="smartpaper-translation-worker",
@@ -81,6 +85,10 @@ class _OrderedTranslationWorker:
81
  def stop_event(self):
82
  return self._stop
83
 
 
 
 
 
84
  def submit(self, job: dict[str, Any]) -> Future:
85
  future = Future()
86
  self._queue.put((future, dict(job)))
@@ -109,6 +117,11 @@ class _OrderedTranslationWorker:
109
  if wait and self._thread.is_alive():
110
  self._thread.join(timeout=2.0)
111
  return
 
 
 
 
 
112
  self._stop.set()
113
  while True:
114
  try:
@@ -936,12 +949,13 @@ class GenerationRunner:
936
  adaptive_structure=adaptive_structure,
937
  target_lang=target_lang,
938
  )
939
- # Capture the worker stop Event itself. `_shutdown_translation_worker()`
940
- # clears `self._translation_worker`; a dynamic self lookup here would
941
- # otherwise let an already-running target call miss task shutdown.
942
- translation_stop_event = self._translation_worker.stop_event
 
943
  translation_agent.set_cancel_checker(
944
- lambda: self.cancel_checker() or translation_stop_event.is_set()
945
  )
946
 
947
  # Backward-compatible resume path for a pre-R3.2.8.3 checkpoint that has
 
70
  self._handler = handler
71
  self._queue = queue.Queue()
72
  self._stop = threading.Event()
73
+ # Lifecycle closure and task cancellation are deliberately distinct.
74
+ # A graceful drain/close before the strict final translation gate must
75
+ # not poison the translation agent with E_TASK_CANCELLED.
76
+ self._cancel = threading.Event()
77
  self._thread = threading.Thread(
78
  target=self._run,
79
  name="smartpaper-translation-worker",
 
85
  def stop_event(self):
86
  return self._stop
87
 
88
+ @property
89
+ def cancel_event(self):
90
+ return self._cancel
91
+
92
  def submit(self, job: dict[str, Any]) -> Future:
93
  future = Future()
94
  self._queue.put((future, dict(job)))
 
117
  if wait and self._thread.is_alive():
118
  self._thread.join(timeout=2.0)
119
  return
120
+ # wait=True is the normal final-gate path after all queued work has
121
+ # been collected. Only an abortive/non-waiting shutdown signals the
122
+ # translation agent to cancel an in-flight model call.
123
+ if not wait:
124
+ self._cancel.set()
125
  self._stop.set()
126
  while True:
127
  try:
 
949
  adaptive_structure=adaptive_structure,
950
  target_lang=target_lang,
951
  )
952
+ # Capture a dedicated abort Event, not the worker lifecycle stop Event.
953
+ # The worker is gracefully closed before the strict final translation
954
+ # gate, but the same translation agent remains valid for deferred/final
955
+ # units. Abortive shutdown still cancels any in-flight target call.
956
+ translation_abort_event = self._translation_worker.cancel_event
957
  translation_agent.set_cancel_checker(
958
+ lambda: self.cancel_checker() or translation_abort_event.is_set()
959
  )
960
 
961
  # Backward-compatible resume path for a pre-R3.2.8.3 checkpoint that has
desktop.ini DELETED
@@ -1,2 +0,0 @@
1
- [.ShellClassInfo]
2
- IconResource=C:\Program Files\Google\Drive File Stream\129.0.1.0\GoogleDriveFS.exe,27
 
 
 
smartpaper_restore_bridge/desktop.ini DELETED
@@ -1,2 +0,0 @@
1
- [.ShellClassInfo]
2
- IconResource=C:\Program Files\Google\Drive File Stream\129.0.1.0\GoogleDriveFS.exe,27
 
 
 
smartpaper_restore_bridge/frontend/desktop.ini DELETED
@@ -1,2 +0,0 @@
1
- [.ShellClassInfo]
2
- IconResource=C:\Program Files\Google\Drive File Stream\129.0.1.0\GoogleDriveFS.exe,27
 
 
 
smartpaper_restore_bridge/frontend/index.html CHANGED
@@ -350,7 +350,12 @@
350
  status.id = "sp-live-translation-status";
351
  status.style.whiteSpace = "pre-wrap";
352
  status.style.fontSize = "0.88em";
353
- status.style.opacity = "0.72";
 
 
 
 
 
354
  status.style.marginBottom = "8px";
355
  status.style.paddingBottom = "4px";
356
  status.style.position = "sticky";
 
350
  status.id = "sp-live-translation-status";
351
  status.style.whiteSpace = "pre-wrap";
352
  status.style.fontSize = "0.88em";
353
+ // The manuscript card owns a fixed white paper surface, so status text
354
+ // must own a fixed high-contrast foreground instead of inheriting the
355
+ // host Streamlit/system dark-theme color. This shared node covers
356
+ // Chinese, English, Russian, and Kazakh interfaces.
357
+ status.style.color = "#374151";
358
+ status.style.opacity = "1";
359
  status.style.marginBottom = "8px";
360
  status.style.paddingBottom = "4px";
361
  status.style.position = "sticky";
static/desktop.ini DELETED
@@ -1,2 +0,0 @@
1
- [.ShellClassInfo]
2
- IconResource=C:\Program Files\Google\Drive File Stream\129.0.1.0\GoogleDriveFS.exe,27
 
 
 
static/previews/desktop.ini DELETED
@@ -1,2 +0,0 @@
1
- [.ShellClassInfo]
2
- IconResource=C:\Program Files\Google\Drive File Stream\129.0.1.0\GoogleDriveFS.exe,27
 
 
 
utils/desktop.ini DELETED
@@ -1,2 +0,0 @@
1
- [.ShellClassInfo]
2
- IconResource=C:\Program Files\Google\Drive File Stream\129.0.1.0\GoogleDriveFS.exe,27