Repository navigation
fix(index): index-generation endpoints report execution wired while no executor exists #174
Description
Summary
The versioned index-generation subsystem exposes six mutating HTTP endpoints and
reports "execution_wired": true, but no code path executes a build. A build
with any work to do can never leave building, and a build for an empty
workspace can be activated while containing zero vectors.
Issue #55 (feat(index): versioned index generations for safe model migration)
is closed as completed. The path it exists to serve — re-embedding a corpus
under a new profile and switching over — cannot currently run.
Source reproduction
On main @ 7a194f1eba4167d54bd46cf84cdbe86e00532319:
- No executor. The target transitions exist only as definitions:
ClaimTargetserver/internal/indexgeneration/service.go:380,
SucceedTarget:475,SkipTarget:491,FailTarget:495,
CleanupExpired:579. Two greps from the repository root, run verbatim:
call sites —
grep -rn '\.\(ClaimTarget\|SucceedTarget\|FailTarget\|SkipTarget\|CleanupExpired\)(' server --include='*.go' | grep -v _test
→ no output; all mentions —
grep -rn 'ClaimTarget\|SucceedTarget\|FailTarget\|SkipTarget\|CleanupExpired' server --include='*.go' | grep -v _test
→ eight lines, the five definitions above plus the comments at:32,:378
and:576. The comment at:378callsClaimTarget"the intended Worker"
entry point. - No reader.
NewSearchResolver(search_resolver.go:22) and
SetGenerationResolver(server/internal/search/generation_routing.go:30)
are likewise never called outside tests, so the resolver is never installed. - Routing discards the generation.
generation_routing.go:63and:74
are_ = genfollowed by a call to the legacy scan, with a comment saying
the vector table is populated by "Worker execution (a later slice)". - Progress can therefore never advance.
refreshProgressis called from
exactly one place,server/internal/indexgeneration/store.go:320, inside
completeTarget, which is reached only from the three unwired target
transitions.state = 'ready'for a real corpus is set only at
store.go:340,347. - Consequence, both directions.
- Non-empty workspace: the build stays
building, soactivate
(store.go:419) fails itsstateAllowedgate and returns
ErrQualityGate(guard atstore.go:457-460). Create → permanently stuck. - Empty workspace:
service.go:208-223marks the buildreadywhen
requiredTargets == 0, and the activation arithmetic
SucceededTargets + SkippedTargets != RequiredTargetsis0 != 0, which
passes. Activating a generation containing no vectors succeeds.
- Non-empty workspace: the build stays
- Retention is not enforced either.
CleanupExpired
(service.go:579) has no non-test caller, soretention_until
(0019_versioned_index_generations.sql:48) is recorded and never acted on. - The documentation says the opposite of the code.
docs/INDEX_GENERATIONS.md:120states the endpoints "expose
execution_wired=false" and that "the server does not expose create, …";
server/internal/api/api.go:249,253,257,261,265,269do expose create,
cancel, resume, activate, rollback, and discard, and
server/internal/api/handlers_index_generations.go:40,63,119,184hard-code
"execution_wired": true.
Expected vs actual
Expected: a status field describes whether execution is wired, and a mutating
endpoint either works or refuses with a reason an operator can act on.
Actual: the field is a literal true; an operator can POST a create, receive a
success, and watch a build that will never move, with no event explaining why.
Scope boundary
This issue is about the mismatch between advertised and real capability, and
about which half is correct. It is not a request to finish the worker slice.
Two mutually exclusive resolutions:
- Smallest: make the flag honest — report
execution_wired: false, align
docs/INDEX_GENERATIONS.md, and have create/activate return an explicit
execution_unavailableso nothing can enter the stuck or empty-activation
states from the API. - Full: add the consumer (
ClaimTarget→ worker →SucceedTarget), install
the resolver incmd/memd/main.go, runCleanupExpiredon a schedule, and
requirerequiredTargets > 0or an explicit empty-corpus acknowledgment before
activation.
The first is a reviewable PR; the second is not, and probably needs its own
issue once a real model migration is on the roadmap.
Acceptance
- One of the two resolutions above is chosen and recorded here, with the
reason, by whoever owns index generation. -
execution_wiredcannot report a state the server does not honor: a test
asserts the flag's value against whether a created build can reach
active. - The empty-workspace activation path is either refused or documented as
intended, with a test for the chosen behavior. -
docs/INDEX_GENERATIONS.mdmatches the routes that exist. - If the full resolution is deferred, an issue for the worker executor is
linked from here rather than left implied.
Evidence level
E2 — source-level and exhaustive for the caller claim (the grep above is
reproducible and its whole result set is "no non-test callers"). Nothing was
executed against a database: the stuck-build and empty-activation behaviors were
derived from the state machine, not observed.
Proposed triage
Applied on filing, per docs/maintainers/triage.md and the precedent in #135:
type:bug, area:server, severity:s2-medium, evidence:e2-source,
status:needs-triage.
Left to a maintainer: priority, and any change to the set below.
The severity is s2-medium rather than higher because no data is lost and no
wrong retrieval is served, but an administrative API reports a capability it
does not have.
Related: #55 (closed completed), #78 and #91 (the merged foundation and
routing slices), docs/INDEX_GENERATIONS.md.
Raised from the data/index audit on 2026-09-08.
Activity
wadrzl commentedon Sep 8, 2026
认领。
前提验证(E2 → E3 进行中):
已确认:
handlers_index_generations.go:40,63,119,184硬编码"execution_wired": trueClaimTarget/SucceedTarget/FailTarget/SkipTarget/CleanupExpired在server/下无非测试调用方(issue 中的 grep 可复现)memd/main.go未安装 generation resolver选择最小修复(理由:worker executor 是独立工作项,不应阻塞诚实性修复):
execution_wired改为falseexecution_unavailable错误,阻止进入 stuck 状态docs/INDEX_GENERATIONS.md对齐不动:worker executor 实现(应另立 issue)
正在本地复现 stuck-build 和 empty-activation 行为,完成后提 PR。
sun-970 commentedon Sep 8, 2026
Resolution: smallest — make the flag honest, block stuck/empty-activation states, align docs.
PR: #182
The full worker executor (ClaimTarget → worker → SucceedTarget, resolver installation, CleanupExpired schedule) is deferred to a follow-up issue once a real model migration is on the roadmap.
wadrzl commentedon Sep 8, 2026
实现完成
选择最小修复,改动如下:
代码变更
server/internal/indexgeneration/types.goErrExecutionUnavailable = errors.New("index generation execution is not wired")server/internal/api/handlers_index_generations.goexecution_wired: true→false(4 处:list/get/create/action)handleCreateIndexGeneration提前返回ErrExecutionUnavailableindexGenerationBuildAction中activate分支返回ErrExecutionUnavailablewriteIndexGenerationError新增ErrExecutionUnavailable处理 → HTTP 503execution_unavailable行为变化
execution_wired: trueexecution_wired: falseexecution_unavailableexecution_unavailable不动
docs/INDEX_GENERATIONS.md更新(可在 PR review 时补)待办
execution_wired值与实际能力一致基线:
main @ 7a194f1eba4PeterGuy326 commentedon Sep 10, 2026
Current-main evidence/status
Clean replacement PR: #189, head
87389fab229cbeba026c1a3b59f0958de2eaf5c5.go test ./internal/api ./internal/indexgeneration: PASS.go test ./...fromserver/: PASS.git diff --check: PASS.errorfield, and the disabled activate path is explicitly verified not to call the service.The old #182 candidate is closed as superseded. #174 remains OPEN pending independent review, exact-head CI, and acceptance; this comment does not claim merge or live release.
PeterGuy326 commentedon Sep 10, 2026
补充状态:堆叠基线 PR #192 已通过完整 CI(含 Web、Go、PostgreSQL、依赖审计)。功能修复 PR #189 的当前差异仅包含 index-generation API、测试、文档和 CHANGELOG;PR 仍 OPEN,等待独立评审,Issue 暂不关闭。
waterbro-8 commentedon Sep 17, 2026
Still open. Draft candidate: #189 (
codex/fix-174-execution-honest) — fail-closedexecution_wired: falseand 503 on create/activate. I am not implementing a generation executor here; that is out of the issue's smallest resolution.mainstill advertises"execution_wired": trueinhandlers_index_generations.go. Tracking #189. No merge or close.docs(index): mark HTTP rollback as 503 until execution is wired
fix(index): tell the truth about unwired generation execution (#174)
waterbro-8 commentedon Sep 20, 2026
平台组分工补派(冯浩然 / waterbro-8)
sun-970,仓库暂不能指派,以钉钉+本评论为准)sun-970 commentedon Sep 20, 2026
Chose the smallest resolution (honest flag, fail-closed create/activate/rollback). Did not implement a worker executor (
ClaimTargetloop).PR: #223 (
sun-970:fix/174-honest-execution-20260920)This is a clean successor to dirty/unmerged #189, not a duplicate of the worker slice. No follow-up executor issue exists yet; that should be filed when a real model migration is on the roadmap.
@waterbro-8 please review.
fix(index): report unwired generation execution honestly (bytefolk#174)
fix(index): report unwired generation execution honestly (#174) (#223)
waterbro-8 commentedon Sep 23, 2026
关闭验收:最小且明确的 resolution 已由 PR #223 合入 main(merge 3977b35;final head 7c9e002)。execution_wired 改为诚实状态,未接线的 create/activate/rollback fail closed,空激活不会被误接受,文档与测试同步。final head 已正式 APPROVED,全部 hosted checks 通过;合入后的 main 四套 workflow 也全绿。完整 worker executor 按 issue 的 scope boundary 不属于本单。