Commit 5c060f59 authored by 郭阔's avatar 郭阔

feat: 部分交付降级为黄色警告(WARNING),不再判失败

- harvest-result.py: 要求N篇仅交付M篇且未取尽时,只要有文章成功入库(succeeded>0)
  → status=WARNING/exit 0,消息进 warnings;交付 0 篇仍判 FAILED
- harvest.sh 报告:WARNING → ⚠️ 成功(部分交付)(邮件仍按成功分支发)
- 面板全站支持黄色徽标:调度中心上次运行/源详情结果状态与历史/运行详情
- 已重判今日 ft 14:30 记录(14/14 交付误判失败→WARNING)并同步修正 last.log
parent 389f6b3e
......@@ -362,9 +362,17 @@ def normalize(envelope, source, count, process_rc, work_dir=None, vault_root=Non
result["warnings"].append(message)
if result["source_exhausted"] and not result["exhaustion_reason"].strip():
fail("INVALID_OUTPUT", "声明已无更多新文章,但未说明检查依据")
partial_delivered = False
if result["attempted_count"] < count and not result["source_exhausted"]:
fail("FETCH_FAILED", f"要求 {count} 篇,仅报告 {result['attempted_count']} 篇,且未确认数据已取尽")
result["status"] = "FAILED" if task_failed else "SUCCESS"
message = f"要求 {count} 篇,仅报告 {result['attempted_count']} 篇,且未确认数据已取尽"
if result["succeeded_count"] > 0:
# 部分交付:已有文章成功入库,列表页候选不足不构成任务失败,降级为警告(WARNING,黄色)
partial_delivered = True
if message not in result["warnings"]:
result["warnings"].append(message)
else:
fail("FETCH_FAILED", message)
result["status"] = "FAILED" if task_failed else ("WARNING" if partial_delivered else "SUCCESS")
output = dict(envelope)
# Preserve the provider's text separately; downstream uses only the verified result.
......
......@@ -348,9 +348,17 @@ fi
# --- 判定状态 ---
# 成功条件:Claude 运行与正文质量、业务结果校验全部通过
if [ "$RC" -eq 0 ] && [ "$IS_ERROR" = "false" ]; then
if command -v jq >/dev/null 2>&1 && [ -s "$JSON_OUT" ] \
&& [ "$(jq -r '.result.status // "SUCCESS"' "$JSON_OUT" 2>/dev/null)" = "WARNING" ]; then
# 部分交付:有文章入库但少于目标,业务上是警告不是失败(黄色)
STATUS_EMOJI="⚠️"
STATUS_TEXT="成功(部分交付)"
STATUS_TAG="WARNING"
else
STATUS_EMOJI="✅"
STATUS_TEXT="成功"
STATUS_TAG="SUCCESS"
fi
else
STATUS_EMOJI="❌"
STATUS_TEXT="失败"
......
......@@ -132,6 +132,7 @@
.badge.unknown { background: #2a2a2a; color: #888; }
.badge.ok { background: #1a3a1a; color: #6bbb6b; }
.badge.fail { background: #3a1a1a; color: #bb6b6b; }
.badge.warn { background: #3a301a; color: #e8c34a; }
/* Buttons */
.btn {
......@@ -204,6 +205,7 @@
.card .value { font-size: 18px; font-weight: 600; color: #e0e0e0; }
.card .value.green { color: #4ec9b0; }
.card .value.red { color: #f44747; }
.card .value.yellow { color: #e8c34a; }
.actions { display: flex; gap: 8px; margin: 16px 0; flex-wrap: wrap; }
.session-id { font-family: monospace; font-size: 12px; color: #569cd6; word-break: break-all; }
......
......@@ -28,7 +28,7 @@
<span class="badge ok" style="font-size:13px">● 运行中</span>
{% elif business_result %}
<span class="badge {{ 'ok' if business_result.status == 'SUCCESS' else 'fail' }}" style="font-size:13px">
{{ '上次成功' if business_result.status == 'SUCCESS' else '上次失败' }}
{{ '上次成功(部分交付)' if business_result.status == 'WARNING' else '上次成功' if business_result.status == 'SUCCESS' else '上次失败' }}
</span>
{% else %}
<span class="badge unknown" style="font-size:13px">无运行记录</span>
......@@ -168,7 +168,7 @@ function confirmContinue(mode, source, fallbackProvider, currentProvider) {
{% if business_result %}
<h2>采集结果{% if result_time %} <span style="font-size:13px;color:#666;font-weight:normal">{{ result_time }}</span>{% endif %}</h2>
<div class="cards">
<div class="card"><div class="label">结果状态</div><div class="value {{ 'green' if business_result.status == 'SUCCESS' else 'red' }}">{{ '成功' if business_result.status == 'SUCCESS' else '失败' }}</div></div>
<div class="card"><div class="label">结果状态</div><div class="value {{ 'yellow' if business_result.status == 'WARNING' else 'green' if business_result.status == 'SUCCESS' else 'red' }}">{{ '成功(部分交付)' if business_result.status == 'WARNING' else '成功' if business_result.status == 'SUCCESS' else '失败' }}</div></div>
<div class="card"><div class="label">成功 / 失败 / 目标</div><div class="value">{{ business_result.succeeded_count }} / {{ business_result.failed_count }} / {{ business_result.requested_count }}</div></div>
</div>
{% for failure in business_result.failures %}
......@@ -223,7 +223,7 @@ function confirmContinue(mode, source, fallbackProvider, currentProvider) {
<td><code>{{ run.run_at }}</code></td>
<td>{{ run.mode }}</td>
<td><span class="badge {{ 'ok' if run.status == 'SUCCESS' else 'fail' if run.status == 'FAILED' else 'unknown' }}">
{{ '成功' if run.status == 'SUCCESS' else '失败' if run.status == 'FAILED' else '旧版记录' if run.status == 'LEGACY' else run.status }}
{{ '成功(部分交付)' if run.status == 'WARNING' else '成功' if run.status == 'SUCCESS' else '失败' if run.status == 'FAILED' else '旧版记录' if run.status == 'LEGACY' else run.status }}
</span></td>
<td>{% if run.requested_count is not none %}{{ run.succeeded_count }} / {{ run.failed_count }} / {{ run.requested_count }}{% else %}—{% endif %}</td>
<td>{{ run.provider }}</td>
......
......@@ -10,7 +10,7 @@
<div class="cards">
<div class="card"><div class="label">运行时间</div><div class="value" style="font-size:14px">{{ run.run_at }}</div></div>
<div class="card"><div class="label">执行类型</div><div class="value" style="font-size:14px">{{ run.mode }}</div></div>
<div class="card"><div class="label">结果状态</div><div class="value {{ 'green' if run.status == 'SUCCESS' else 'red' if run.status == 'FAILED' else '' }}">{{ '成功' if run.status == 'SUCCESS' else '失败' if run.status == 'FAILED' else '旧版记录' if run.status == 'LEGACY' else run.status }}</div></div>
<div class="card"><div class="label">结果状态</div><div class="value {{ 'yellow' if run.status == 'WARNING' else 'green' if run.status == 'SUCCESS' else 'red' if run.status == 'FAILED' else '' }}">{{ '成功(部分交付)' if run.status == 'WARNING' else '成功' if run.status == 'SUCCESS' else '失败' if run.status == 'FAILED' else '旧版记录' if run.status == 'LEGACY' else run.status }}</div></div>
<div class="card"><div class="label">Provider</div><div class="value" style="font-size:14px">{{ run.provider }}</div></div>
<div class="card"><div class="label">耗时</div><div class="value">{{ run.duration }}</div></div>
</div>
......
......@@ -106,8 +106,10 @@ function toggleEdit(name) {
<td>
{% if r.last %}
{{ r.last.mtime }}<br>
{% if '成功' in (r.last.status or '') %}<span class="badge ok">{{ r.last.status }}</span>
{% elif r.last.status %}<span class="badge fail">{{ r.last.status }}</span>{% endif %}
{% set st = r.last.status or '' %}
{% if '部分交付' in st or '⚠' in st %}<span class="badge warn">{{ st }}</span>
{% elif '成功' in st %}<span class="badge ok">{{ st }}</span>
{% elif st %}<span class="badge fail">{{ st }}</span>{% endif %}
{% else %}<span style="color:#666">从未</span>{% endif %}
</td>
<td>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment