恢复 terminalLibraryCaptureError,但仅限仍存在的 missing library generated question index 和 empty library index content;已恢复写入者时走 jobs.Permanent(validation_failed),保留原消息。已取消的正文索引覆盖 marker 和网络超时仍重试。部署脚本另以新包提供旧基线稳定性采样;不恢复 R3f 已取消 的正文索引/父类型规则。 验证:worker 保留错误 RED→GREEN、v071、Go 全量、make verify 17 项。
This commit is contained in:
+21
-2
@@ -1,5 +1,24 @@
|
||||
# Changelog
|
||||
|
||||
## 开发快照 0.1.364(恢复保留错误的第一因分类;部署基线稳定性)
|
||||
|
||||
### Fixed
|
||||
|
||||
- worker 恢复 `terminalLibraryCaptureError`,仅保留仍存在的两个确定性 marker:
|
||||
`missing library generated question index`、`empty library index content`。已恢复
|
||||
写入者后走 `jobs.Permanent(validation_failed)`,保留原错误消息;已取消的正文
|
||||
索引覆盖 marker 和网络超时仍可重试,不再恢复推断门槛。
|
||||
- 本机部署 preflight 不再用 lifetime `RestartCount=0` 作为旧基线稳定性定义:
|
||||
绑定容器 ID/image/env/mount/StartedAt/RestartCount,间隔采样确认 running、
|
||||
StartedAt/RestartCount 不变;历史非零但稳定允许,采样变化/切换实例拒绝。
|
||||
新 api/worker/web 容器仍要求 running、ready、零重启。
|
||||
|
||||
### Tests
|
||||
|
||||
- 保留错误分类 RED→GREEN:`r3g-terminal-red.txt` / `r3g-terminal-green.txt`。
|
||||
- 部署 strict fake 增加旧基线非零稳定正例、RestartCount 递增拒绝、实例 ID 切换
|
||||
拒绝;本机候选包重新绑定最终 SHA。
|
||||
|
||||
## 开发快照 0.1.363(取消封存索引推断规则,原样捕获源集合)
|
||||
|
||||
### Removed
|
||||
@@ -10,8 +29,8 @@
|
||||
- 删除 `parent_chunk_id` 的类型搭配门槛:不再要求 parent 只能是 `parent_text`,也不
|
||||
对 summary/OCR/caption 指定 parent 类型。保留父引用存在、同 knowledge 等实际引用
|
||||
完整性;不补关联、不改源数据。
|
||||
- 同步移除该推断在 preflight/archive/load/replay/writeset 的共用校验和已无用途的
|
||||
worker 永久失败分类;旧快照、旧失败记录原样保留,不篡改历史状态。
|
||||
- 同步移除该推断在 preflight/archive/load/replay/writeset 的共用校验和当时已无
|
||||
用途的 worker 永久失败分类;旧快照、旧失败记录原样保留,不篡改历史状态。
|
||||
- 0.1.362 的索引覆盖门槛未部署,现被本版本取消;0.1.362 原文保留为历史,不再作为
|
||||
当前契约。
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"knowledge-governance/internal/jobs"
|
||||
)
|
||||
|
||||
// R3g: only retained deterministic capture failures become permanent after the
|
||||
// agent has recovered the writer. Cancelled body-index coverage markers are
|
||||
// deliberately absent.
|
||||
func TestRetainedLibraryCaptureFailuresArePermanent(t *testing.T) {
|
||||
for _, marker := range []string{
|
||||
"missing library generated question index",
|
||||
"empty library index content",
|
||||
} {
|
||||
t.Run(marker, func(t *testing.T) {
|
||||
original := errors.New("LIBRARYCTL_FAILED: " + marker + ";已执行 recover 并确认写入者恢复")
|
||||
got := terminalLibraryCaptureError(original)
|
||||
terminal, code := jobs.Terminal(got)
|
||||
if !terminal || code != jobs.ErrCodeValidationFailed {
|
||||
t.Fatalf("retained validation failure must park immediately: terminal=%v code=%q err=%v", terminal, code, got)
|
||||
}
|
||||
if got.Error() != original.Error() {
|
||||
t.Fatalf("original message changed: got %q want %q", got.Error(), original.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelledCoverageFailureStaysRetryable(t *testing.T) {
|
||||
for _, marker := range []string{
|
||||
"unverified legacy library chunk index coverage",
|
||||
"missing indexed library chunk",
|
||||
} {
|
||||
err := terminalLibraryCaptureError(errors.New(marker + ";已执行 recover 并确认写入者恢复"))
|
||||
if terminal, code := jobs.Terminal(err); terminal {
|
||||
t.Fatalf("cancelled marker %q must not be terminal; code=%q", marker, code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransientLibraryCaptureFailureStaysRetryable(t *testing.T) {
|
||||
for _, message := range []string{
|
||||
"library agent is unreachable",
|
||||
"context deadline exceeded",
|
||||
`LIBRARYCTL_FAILED: job "lib-internal-x" already exists with state "failed";已执行 recover 并确认写入者恢复`,
|
||||
"missing library generated question index; writer restore not confirmed",
|
||||
} {
|
||||
got := terminalLibraryCaptureError(errors.New(message))
|
||||
if terminal, code := jobs.Terminal(got); terminal {
|
||||
t.Fatalf("%q must stay retryable, got terminal code=%q", message, code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetainedFailureDoesNotChangeMessage(t *testing.T) {
|
||||
original := errors.New("LIBRARYCTL_FAILED: missing library generated question index;已执行 recover 并确认写入者恢复")
|
||||
got := terminalLibraryCaptureError(original)
|
||||
if !strings.Contains(got.Error(), "missing library generated question index") {
|
||||
t.Fatalf("lost original cause: %v", got)
|
||||
}
|
||||
}
|
||||
+22
-1
@@ -101,6 +101,27 @@ func stageSizesFrom(manifest librarysnapshot.Manifest) map[string]stageSize {
|
||||
// libraryCaptureJobType is shared with the API which enqueues it.
|
||||
const libraryCaptureJobType = "library.capture"
|
||||
|
||||
// Retained deterministic source-content failures: the agent has already
|
||||
// restored the writer, so retrying the same journal only replaces the first
|
||||
// cause with "already exists". Body-index coverage markers are intentionally
|
||||
// absent; that inferred rule was removed in R3f.
|
||||
var terminalLibraryCaptureMarkers = []string{
|
||||
"missing library generated question index",
|
||||
"empty library index content",
|
||||
}
|
||||
|
||||
func terminalLibraryCaptureError(err error) error {
|
||||
if err == nil || !strings.Contains(err.Error(), "已执行 recover 并确认写入者恢复") {
|
||||
return err
|
||||
}
|
||||
for _, marker := range terminalLibraryCaptureMarkers {
|
||||
if strings.Contains(err.Error(), marker) {
|
||||
return jobs.Permanent(jobs.ErrCodeValidationFailed, err)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// librarySyncJobType 是生产同步作业的队列类型;与封存严格分开,状态不共用。
|
||||
const librarySyncJobType = "library.sync"
|
||||
|
||||
@@ -365,7 +386,7 @@ func workerHandlers(store *postgresstore.Store, config appconfig.Config) (map[st
|
||||
_ = store.AdvanceLibraryJob(ctx, libraryJobID, governance.LibraryJobFailed, "export", err.Error(),
|
||||
"agent 已执行恢复检查;确认来源 healthy 后可重试同一作业号", "", "", finishedAt)
|
||||
log.Printf("library capture failed scope=%s capture_job=%s: %v", payload.Scope, payload.CaptureJob, err)
|
||||
return err
|
||||
return terminalLibraryCaptureError(err)
|
||||
}
|
||||
// 执行后复核:结果里 agent 自报的身份必须还是期望实例,否则这次封存
|
||||
// 可能来自别的栈,绝不能登记成"本实例的测试封存"。
|
||||
|
||||
Reference in New Issue
Block a user