Drive the wizard off the article locale instead of the UI locale so an
en-US article stays in English end to end, and stop Chinese values from
leaking into English drafts.
- Localize review-intro-hook copy and outline section labels to English
(with fallbacks), and use a ": " separator for en-US
- Sanitize CJK content from titles, outline, and key points when the
article locale is en-US, and re-sanitize on locale switch/draft restore
- Add knowledge-base reference labels/placeholders and the
missing-review-intro-hook validation message to both locales
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When the article locale is en-US, Chinese prompt templates could leak
Chinese wording into generated titles, outlines, and article bodies.
Add high-priority language-consistency guards so the model treats the
Chinese template text as internal instructions and emits English only.
- Append per-artifact locale guards (analyze/title/outline) in template
assist prompts and an article-body guard in the generation prompt,
only when locale is en-US
- Reinforce locale consistency in the title/outline runtime prompts and
drop retained images from the rewrite prompt
- Cover the new guards with unit tests
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Previously AI point cost was computed from request (input) characters at
reservation time. Switch to reserving a single point up front and
settling the final cost from the generated output length on completion.
- Reserve 1 point (or FixedPoints) instead of pricing on request chars
- On completion, recompute points from output chars vs base chars,
update the reservation amounts, and post a ledger delta for the
top-up/refund; invalidate the workspace quota summary cache
- MarkCompleted now persists final request_chars/base_chars/points
- Use ceil division in calculateAIPointCost so an exact base boundary
charges one point instead of rolling over
- Thread output text through all CompleteAIPoints callers (article
selection, KOL assist, question expansion, template assist, compliance
judge) and return the settled reservation
- Add unit tests plus an integration test gated on TEST_DATABASE_URL
- Update the user manual: billing is by output characters
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the hardcoded doubao-lite model used for monitoring answer
parsing and compliance LLM judging with configurable values, resolved
from config with env overrides and a legacy default fallback.
- Add llm.monitoring_answer_parse_model and compliance.llm_judge_model
to config struct, env overrides, and all config files
- Thread the resolved model through MonitoringCallbackService via a
ConfigProvider and into parseMonitoringAnswerWithLLM
- Pass compliance.llm_judge_model into the review-job LLM request
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remove the recentArticlesQuery fallback path so the templates record
table renders straight from the article list query, simplifying polling,
pagination and loading state.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GetRecentArticlesByBrand now folds the latest publish record per target
into an aggregated publish_status (publishing / partial_success / success
/ failed), falling back to the stored status when no records exist.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Aggregate publish status from the latest record per publishing target
using a shared target-identity expression, so retries and multi-record
targets no longer inflate the status buckets.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Unify list/detail poll intervals to 5s and skip refetch while a query is
already in flight, replacing broad invalidateQueries cascades with targeted
refetches. Poll now also triggers on active publish status via the new
hasActivePublishStatus helper. Dedupe concurrent refreshBrands calls with a
shared promise and skip the redundant AppShell refresh when already
initialized. Gate publish-record loading on popover open.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add CancelStaleQueuedPublishTasks to abort publish tasks that sit in the
queue past a configurable timeout (default 3 days) without being claimed by
a desktop client, so they no longer linger indefinitely as 'queued'. The
lease recovery worker runs the cleanup each cycle and reports a
cancelled_queued count; the timeout is configurable via job run config.
Aborted tasks carry a publish_queue_timeout error payload with a readable
Chinese duration, and the admin-web publish summary surfaces it as an
auto-cancelled queue-timeout message.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add normalizeDesktopTaskCompletionStatusForTask so an "unknown" publish
completion is downgraded to "failed" when the payload is a manual retry or
the error matches a definitive publish failure, instead of leaving it
stuck as unknown.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the in-place requeue of submit-uncertain unknown publish tasks
with an explicit supersede-and-create-new flow: manual retries mark the
old unknown task failed (manual_retry_superseded) and create a fresh task
carrying manual_retry / superseded_unknown_task_ids in its payload.
Also fold title-length validation into definitivePublishFailurePattern and
check the pattern before the publish_submit_uncertain guard so those
failures are released from the dedup set.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the definitive-failure regex into a named constant and add title
length/count validation patterns so submit-phase failures like
"标题长度应该在2-30字之间" stay non-retryable instead of being classified
as uncertain.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a sort_order column to brands with a migration, expose a
PUT /api/tenant/brands/order reorder endpoint, and wire the
admin-web BrandsView with drag-and-drop reordering plus i18n.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Publish records with statuses like queued, pending, running, cancelled,
or unknown fell through the display map and rendered as raw enum values.
- Add queued/pending/running/cancelled/canceled/unknown entries to the
publish status map with matching zh-CN and en-US translations
- Normalize status keys (trim + lowercase) before lookup so backend
casing variants still resolve
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rotated refresh tokens now stay valid for a 60s grace window so
concurrent refreshes (e.g. multiple browser tabs) each obtain a valid
new pair instead of being logged out. Admin-web additionally serializes
refreshes across tabs via the Web Locks API and reuses tokens already
rotated by another tab.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>