Commit Graph

684 Commits

Author SHA1 Message Date
root 555b0abc72 chore(release): bump desktop-client version to 0.1.12
Desktop Client Build / Resolve Build Metadata (push) Successful in 39s
Frontend CI / Frontend (push) Successful in 3m35s
Backend CI / Backend (push) Successful in 24m53s
Desktop Client Build / Build Desktop Client (push) Successful in 26m46s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 37s
2026-07-21 08:42:13 +08:00
root 25903a36a0 docs(manual): document paste-text source mode for imitation create
Update the imitation section for the new source-method toggle (URL
extraction or pasted text with the 24,000-character limit) and reformat
module tables.
2026-07-21 08:42:09 +08:00
root ce67faadfb feat(prompts): require real local competitors in imitation ranking lists
In ranking or recommendation entries, competitors from the source
article must be replaced with verifiable local companies matching the
target brand's region and business scope; category-style placeholder
names are forbidden, and unverifiable entries are dropped instead of
kept or invented.
2026-07-21 08:42:06 +08:00
root e497f26d58 feat(admin-web): add paste-text source mode to imitation create page
- Add a source-method toggle (article URL / pasted text) with per-mode
  hints, a 24,000-character counter, and mode-aware submit validation
- Validate URLs client-side (http/https only) with a dedicated error
  message; only the active mode's field is sent to the API
- Keep URL mode selected when arriving with source_url query params
- Refresh the page layout and update zh-CN/en-US copy for both modes
2026-07-21 08:42:01 +08:00
root d62f7b3c91 feat(imitation): accept pasted source content as an alternative to URL
- Make source_url optional and add source_content to the request; the
  two are normalized into a source kind ("url" | "content"), URL wins
  when both are present, and missing both returns source_required
- Skip web fetching in the generation worker when pasted content is
  provided; truncate it to the same 24,000-rune cap
- Label untitled pasted-content jobs with a locale-aware display title
  and mark the source kind in wizard state and prompt metadata
- Cover source normalization, truncation, and display title with tests
2026-07-21 08:41:55 +08:00
root 403ff91789 docs(kb): add company info fact sheet to knowledge base
Desktop Client Build / Resolve Build Metadata (push) Successful in 53s
Backend CI / Backend (push) Successful in 17m1s
Desktop Client Build / Build Desktop Client (push) Successful in 25m33s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 33s
Source material backing the rewrite-prompt requirement to cite real
brand numbers from the company knowledge base.
2026-07-18 21:16:12 +08:00
root 89a300c458 docs(plan): mark generated-code drift phases 69-70 complete
- Record deterministic sqlc output (identical checksum across runs) and
  the migration source of the media-supply favorite tables
- Note external commits 3037cfe/6adcec4 that landed the generated fix
  and that CI reproduction now passes on origin/main
- Advance task plan to Phase 70 complete with tests and scope guard green
2026-07-18 21:16:08 +08:00
root efe1cde77c feat(prompts): surface brand KB numbers and genericize competitor figures
- Require rewrite output to weave in verifiable numbers from the brand
  knowledge base, web search, or company profile to highlight advantages
  and credibility
- Rewrite competitor-specific numbers into plain, unremarkable wording
  (e.g. "1000+ stores" becomes "nationwide store coverage")
- Keep article length and structure aligned with the source article
  instead of the fixed ~2000-character target
2026-07-18 21:16:03 +08:00
root 457d8c1890 feat(kimi-adapter): query Kimi Connect stream API with page RPA fallback
- Call the kimi.com apiv2 ChatService/Chat endpoint directly using
  Connect+JSON framing: encode the request as a length-prefixed frame,
  decode streamed frames, and summarize set/append events into answer,
  reasoning, sources, and capacity notices
- Fall back to the existing page RPA flow (mode switch + DOM polling)
  when the API transport fails or yields no usable summary
- Switch the target model from K2.6 fast to K3
- Treat capacity notices as terminal answers: include them in snapshot
  signature/content checks and broaden the capacity-limit pattern
2026-07-18 21:15:57 +08:00
root 6adcec4849 feat: complete Phase 69 of generated-code drift diagnosis and update task plan status 2026-07-15 00:04:24 +08:00
root 3037cfe059 feat: add MediaSupplyFavorite types and update task plan for generated-code drift diagnosis
Backend CI / Backend (push) Successful in 17m27s
2026-07-15 00:04:13 +08:00
root 3cb15ab5a3 docs: update planning artifacts for platform challenge handling
Desktop Client Build / Resolve Build Metadata (push) Successful in 32s
Backend CI / Backend (push) Failing after 8m13s
Desktop Client Build / Build Desktop Client (push) Successful in 24m4s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 32s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 22:01:54 +08:00
root aa9ce6f23e feat(desktop): pause a platform after its last account hits a challenge
Add a per-platform circuit breaker that trips when a monitor task's final
account fails over with risk_control / challenge_required /
authorization_failed. Tripping cancels the platform's remaining pending
local monitor tasks (aborted with a cancellation summary) and blocks new
ones until an account probes healthy or a fresh account is bound. Adds
cancelPendingMonitorTasksForPlatform to the monitor scheduler plus tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 22:01:48 +08:00
root 5c3f2c7822 feat(desktop): surface runtime alerts as system notifications
Add a runtime system notifier that pushes danger-severity activity (and
forced account-access alerts) to the OS via the tray balloon on Windows,
falling back to Electron Notification elsewhere, with a 30s per-key
dedupe window. Route risk-control / human-verification account alerts
through it so users are notified when an account needs attention.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 22:01:38 +08:00
root 1fab7b1e5f feat(monitoring): scope authorization-failure cancellation to platform across accounts
When a monitor task's final account hits human verification or an
authorization failure, cancel the remaining queued desktop/monitoring
tasks for the whole platform instead of only the same account. Follow-up
tasks are now marked skipped/aborted (not failed) with a
platform_human_verification / platform_authorization_unavailable reason
and a user-facing cancellation message, and emit task_canceled lifecycle
events for monitor kinds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 22:00:41 +08:00
root b0bf9b4299 feat(qwen): implement source fallback mechanism and add tests for settled page sources
Desktop Client Build / Resolve Build Metadata (push) Successful in 36s
Desktop Client Build / Build Desktop Client (push) Successful in 23m42s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 33s
2026-07-14 10:51:15 +08:00
root 75c9be5eb3 chore(release): update desktop-client version to 0.1.11 and document July 12 release audit
Desktop Client Build / Resolve Build Metadata (push) Successful in 26s
Desktop Client Build / Build Desktop Client (push) Successful in 25m23s
Desktop Client Build / Publish Client Artifacts to NAS (push) Failing after 50s
2026-07-12 17:01:23 +08:00
root e68db14802 docs(plan): update planning artifacts for AI accounts and adapter work
Desktop Client Build / Resolve Build Metadata (push) Successful in 30s
Frontend CI / Frontend (push) Successful in 5m4s
Desktop Client Build / Build Desktop Client (push) Successful in 26m59s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 52s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 14:57:25 +08:00
root 62ef01463e feat(desktop-ui): show account avatar image in AI platforms table
Render the account avatarUrl when present, falling back to the initial
letter, with cover sizing inside the avatar circle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 14:57:25 +08:00
root 977ffb1335 fix(yuanbao-adapter): correct fragment merge and json candidate parsing
Stop dropping short repeated fragments in mergeText (append them unless
the duplicate is long enough to be a real echo) and drop the unreliable
reverse-overlap branch. Return early from extractJSONCandidates when the
whole body parses, and drop the seen-set so line-level frames are no
longer deduped away.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 14:57:25 +08:00
root d2cb2faa61 refactor(admin-web): move answer markdown normalization to a tested lib
Extract normalizeLooseMarkdownLine from TrackingQuestionDetailView into
a shared monitoring-answer-markdown module and harden it (model bullet
`**-` and `*` handling). Add a vitest runner and unit tests for the
normalization rules.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 14:57:16 +08:00
root a04d41b230 feat(admin-web): extract AI account management into its own page
Move the AI-platform account status cards out of TrackingView into a
dedicated AIAccountsView, registered at /tracking/ai-accounts with a nav
entry and route/nav i18n strings. Keeps the tracking dashboard focused
while giving accounts, authorization state and desktop runtime nodes a
first-class page.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 14:57:16 +08:00
root a02ed4e79f docs(plan): update planning artifacts for adapter and account-pool work
Desktop Client Build / Resolve Build Metadata (push) Successful in 24s
Frontend CI / Frontend (push) Successful in 2m56s
Backend CI / Backend (push) Failing after 8m6s
Desktop Client Build / Build Desktop Client (push) Successful in 24m4s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 50s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 14:17:36 +08:00
root 06dafa88f8 test(tenant): cover desktop task platform id dedup and target count
Assert uniqueMonitorDesktopTaskPlatformIDs trims and collapses duplicate
account specs, and tighten the healthier-candidate case with a target
length check. Apply gofmt alignment fixes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 14:17:36 +08:00
root 177087b41b fix(admin-web): preserve paragraph breaks when sanitizing answer body
Keep blank lines while filtering non-answer noise instead of collapsing
every line, so multi-paragraph answers render with their structure
intact. Also reformat long box-shadow declarations and inline template
attributes for readability.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 14:17:36 +08:00
root 16e73438c4 feat(desktop-ui): AI platforms multi-account binding and probe view
Rework the AI platforms view around multiple accounts per platform:
per-account auth-state classification, status/platform filtering, and an
inline health probe (verifyAccount) with pending state. Update the nav
description to reflect multi-account binding, health checks and auto
switching.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 14:17:27 +08:00
root 2706c07381 feat(desktop-monitor): multi-account pool with failover and cooldown
Add monitor-account-pool to select authorized, non-blocked candidates
for an AI-platform monitor task, classify failover reasons (risk
control, challenge, auth failure, empty/unknown result) and cool the
account down before rotating to the next. Wire runtime-controller to run
monitor tasks through the pool, retrying across accounts and annotating
the result with per-account attempt diagnostics and a failover count.
Expose the pool state via the runtime snapshot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 14:17:27 +08:00
root 70b9f75aea feat(yuanbao-adapter): match chat SSE by question and keep answer breaks
Filter captured `/api/chat/*` event-stream responses down to the one
whose request prompt matches the current question, avoiding cross-talk
between concurrent conversations. Preserve blank lines when sanitizing
answer candidates so paragraph breaks survive, and always trust the
parsed SSE answer over the DOM scrape.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 14:17:14 +08:00
root bbc2d89450 feat(qwen-adapter): capture chat SSE and expand tab_container cards
Attach a response listener to the `/api/v2/chat` POST stream, parse its
SSE payloads, and reconstruct answer content/extra_info/communication
from the `multi_load/iframe` and `bar/iframe` messages. Expand embedded
`[(tab_container_N)]` references against the SSE cardMap so nested tab
content is inlined instead of leaking a raw placeholder. Prefer the API
answer, falling back to page state, and record `response_source` plus
`api_event_count` in the raw response for diagnosis.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 14:17:14 +08:00
root b70dc9dc6d test(qwen-adapter): cover tab-container placeholder handling
Add query-level cases asserting an internal placeholder yields
`unknown`/`qwen_incomplete_response`, and that a resolved sibling field
is used as the answer when another field is still a placeholder.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 11:55:13 +08:00
root 6568d08a47 feat(qwen-adapter): reject internal tab-container placeholder as answer
When Qwen returns an unresolved `[(tab_container_N)]` placeholder in
multiLoadIframe/barIframe content, treat it as an incomplete response:
fall back to a resolved sibling field when available, otherwise return
status `unknown` with a `qwen_incomplete_response` error so the record
is retried on a later collection pass instead of persisting garbage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 11:55:08 +08:00
root 04c89c6d4e chore(deploy): point k3s frontend image at latest tag
Deployment Config CI / Deployment Config (push) Successful in 39s
Desktop Client Build / Resolve Build Metadata (push) Successful in 47s
Frontend CI / Frontend (push) Successful in 4m33s
Backend CI / Backend (push) Failing after 8m13s
Desktop Client Build / Build Desktop Client (push) Successful in 24m20s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 54s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 20:45:19 +08:00
root b6858d2605 docs(plan): record planning artifacts for recent work streams
Add task_plan/findings/progress notes for knowledge fact fidelity,
brand description context, media supply favorites, and the workspace
sync-to-39 deployment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 20:45:03 +08:00
root 67a6cbcd9e feat(media-supply): persist favorites with multi-group membership
Move media favorites from client state to PostgreSQL with server-side
search and pagination.

- Store favorites keyed by (tenant, user, group, resource) so a resource
  can belong to multiple groups; the 500-resource cap counts distinct
  resources, not memberships.
- Add favorite-group CRUD and group/global removal routes, with silent
  cleanup of delisted or invisible resources on read.
- Serve favorite resource details server-side, 10 per page, with name/ID
  search; favorites-page removal is group-scoped, resources-page removal
  is global.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 20:21:59 +08:00
root 0bf4b73ebc feat(tenant): inject brand description context into every generation path
Include the current brand description in template, custom, imitation,
and KOL article-generation prompts while bounding prompt growth.

- Add a shared brand-context builder that resolves the current brand,
  compacts long descriptions, and caps rendered output at 2000 runes.
- Snapshot a structured brand prompt context on queued tasks so old
  jobs stay reproducible and retries stay stable.
- Route brand-profile facts through the existing typed fact guard so
  founding dates and year counts get the same pre-persistence validation
  as RAG facts, with brand facts outranking conflicting RAG facts.
- Fix the KOL creator to attach the brand scope its worker consumes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 20:21:59 +08:00
root 418b3c4998 feat(tenant): guard numeric knowledge facts against silent contradiction
Ensure numeric facts present in retrieved knowledge (especially company
founding dates) cannot be silently contradicted in generated articles.

- Add a typed fact guard that extracts constraints (dates, experience
  years, etc.) from precise facts, detects source conflicts, and
  validates generated content before persistence with a bounded repair
  retry.
- Surface fact constraints through KnowledgeContext and render them as
  a canonical, non-derivable fact block in the knowledge prompt section.
- Tighten prompt intro lines to forbid rewriting, mixing old values,
  or deriving service years from founding dates.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 20:21:59 +08:00
root 5463319b40 feat(desktop): default Kimi to fast mode and show release notes on update
- kimi adapter: parameterize mode switching (fast/thinking) and default to
  K2.6 快速; fix snapshot filtering so fast-mode "搜索网页" chips no longer
  wipe the answer body or get misclassified as reasoning/sidebar
- desktop shell: display release notes in the client update modal
- admin-web: fix publish-records table layout with fixed columns and ellipsis
- bump desktop-client to 0.1.10

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 01:35:08 +08:00
root 347cea1296 feat(llm): add configurable request/token rate limiting for LLM client
Introduce process-local and Redis-backed global rate limiting for the
shared LLM client, plus a dedicated generation consumer prefetch knob.

- Add request (RPM) and token (TPM) rate limits with burst controls,
  process or global scope, and fail-closed/process-degraded failover
- Wire the LLM client through NewWithRedis so limits can be shared
  across replicas via a Redis token bucket
- Add generation_consumer_prefetch to tune RabbitMQ generation
  consumers independently of the default prefetch
- Bump generation worker_concurrency to 24 and promote golang.org/x/time
  to a direct dependency
- Drop t.Parallel() from a few middleware/bootstrap tests

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 00:14:40 +08:00
root 0acd37918e feat(admin-web): localize template wizard for en-US articles
Deployment Config CI / Deployment Config (push) Successful in 47s
Frontend CI / Frontend (push) Successful in 3m14s
Backend CI / Backend (push) Successful in 16m45s
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>
2026-07-09 19:39:29 +08:00
root 2c394d436a feat(tenant): enforce English output for en-US template generation
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>
2026-07-09 19:38:55 +08:00
root f69edc2218 feat(tenant): bill AI points by output characters
Deployment Config CI / Deployment Config (push) Successful in 39s
Backend CI / Backend (push) Successful in 18m14s
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>
2026-07-09 17:04:37 +08:00
root c8dceb43d7 feat(tenant): make monitoring parse & compliance judge models configurable
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>
2026-07-09 17:04:01 +08:00
root fb142e4ca7 docs(swagger): document brand order endpoint
Backend CI / Backend (push) Successful in 18m19s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 23:57:56 +08:00
root 8300d12b20 chore(desktop-client): bump version to 0.1.9
Desktop Client Build / Resolve Build Metadata (push) Successful in 30s
Frontend CI / Frontend (push) Successful in 3m28s
Backend CI / Backend (push) Failing after 11m56s
Desktop Client Build / Build Desktop Client (push) Successful in 29m6s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 30s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 23:39:18 +08:00
root 1bc4df958f refactor(admin-web): drop recent-articles fallback from templates records
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>
2026-07-08 23:39:18 +08:00
root e90d6a185f feat(tenant): derive recent article publish status from publish records
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>
2026-07-08 23:39:07 +08:00
root 58a9b379bc feat(tenant): dedup article publish status by latest record per target
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>
2026-07-08 23:38:59 +08:00
root 5d29703265 perf(admin-web): reduce redundant polling and cover active publish status
Frontend CI / Frontend (push) Successful in 3m35s
Backend CI / Backend (push) Failing after 9m46s
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>
2026-07-08 23:16:47 +08:00
root 2c11910b6c chore(admin-web): add favicon
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 22:56:45 +08:00
root 832d7f507d feat(publish): cancel stale queued publish tasks after queue timeout
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>
2026-07-08 22:56:37 +08:00