Repository navigation
Description
Impact / 影响
examples/explore-todo-result-node-linkage-smoke.py fails deterministically on current main, so the nightly Full Public Smokes sweep is red for this smoke and contributors lose a green signal for the Explore→archive linkage guarantee it exists to protect (#1819).
The failure is a self-contradiction inside one run: the same Todo keeps its explore_result_node_refs through the readback path, but the shipped smoke also requires the token to still be rendered inline in the display Markdown after todo archive-completed, and that inline repetition is gone.
Preflight
- I searched existing issues and discussions for this behavior.
- This report is not an unpatched security vulnerability.
- The report and attachments contain no credentials or private/internal material.
Issue origin
Reproduced in a real environment (clean source checkout of main, local runner, no model calls).
LoopX version or commit
4d8b79692d13ea17a43d2369d35282b023be311e (current main). The same failure is recorded in the scheduled Full Public Smokes run 41937099939 (shard 3, 2026-11-05T00:00:07Z).
Host or runtime surface
Not host-specific. Python 3.12 / macOS runner; synthetic fixture data only.
LoopX area
Control plane (todos, archive projection).
Problem
check_todo_lifecycle asserts the same linkage token at three points, and they do not agree:
| Step | Assertion | Result |
|---|---|---|
after todo complete |
explore_result_node_refs == ["node_live", "node_dead"] on the terminal Todo (:156) |
passes |
after todo complete |
the active state Markdown contains explore_result_node_refs=node_live%2Cnode_dead (:158) |
passes |
after todo archive-completed --max-active-done 0 --execute |
the archived state Markdown contains explore_result_node_refs=node_live%2Cnode_dead (:172) |
fails |
after todo archive-completed |
todo list --todo-id <id> still returns archive_state == "archive" and explore_result_node_refs == ["node_live", "node_dead"] (:176-177) |
passes |
The rendered archive section after the drop contains only pointer comments, with no item rows and no refs token:
## Completed Work Archive
<!-- loopx:todo-region-v0 role=archive begin -->
<!-- loopx:todo-section-projection-v0 role=archive provider_revision=sqlite:<digest>:4 records_sha256=<digest> -->
<!-- loopx:todo-archive-pointer authority=sqlite_v0 archived_count=1 active_done_omitted=0 query="loopx todo list --goal-id <goal-id> --include-archived" -->
<!-- loopx:todo-archive-pointer authority=sqlite_v0 archived_count=1 active_done_omitted=0 goal_id=explore-todo-linkage-smoke query="loopx todo list --goal-id explore-todo-linkage-smoke --include-archived" -->
<!-- loopx:todo-region-v0 role=archive end -->
So the authority readback is intact (the archived record and its explore_result_node_refs are still readable through --include-archived), while the display projection no longer repeats the token inline. The shipped smoke still requires the inline form. One of the two is wrong, and I cannot decide which from source inspection alone, so I am reporting the gap instead of changing either side.
Minimal reproduction
uv sync --extra test
PYTHONUTF8=1 python examples/explore-todo-result-node-linkage-smoke.pyObserved twice in a row on a clean checkout, both times at the same line:
File "examples/explore-todo-result-node-linkage-smoke.py", line 172, in check_todo_lifecycle
assert "explore_result_node_refs=node_live%2Cnode_dead" in archived, archived
AssertionError
Expected behavior
One owned answer, recorded where the archive projection contract lives:
- if archived items are represented by a pointer plus
--include-archivedreadback (which is what the projection code now does, and what:177already proves), then the shipped smoke should assert the pointer and the readback instead of inline repetition, and the Explore linkage guarantee should be stated in terms of the readback path; or - if the inline archive record is still the guarantee, the archive section lost it and this is a projection regression.
Actual behavior
The two surfaces disagree, and the shipped public smoke fails on main.
Existing related work / what is not duplicated here
- Explore planner: add explicit todo-to-result-node linkage before typed evidence scoring #1819 introduced the Todo→result-node linkage that this smoke guards (closed).
- fix(ci): restore strict qualification and reliable asynchronous readback #8013 is open and touches
loopx/control_plane/todos/machine_section_projection.py, but only with typing/castcleanups (+4/−3) that do not change archive rendering, so this behavior is not being repaired there. - Precedent for the shape of this report: [Bug]: two shipped public smokes now contradict #7587's projection contract and fail on main (hot-path quota payload) #7653, where two shipped smokes contradicted the accepted projection contract and the consumers were reconciled to it.
Scope of this claim
One smoke, two local reruns plus one hosted nightly record. I am not claiming the whole nightly fleet's state, not claiming a data-loss or authority defect, and not claiming which side should change.
中文补充:归档条目现在只留指针,正文里不再重复 explore_result_node_refs;但用 --include-archived 回读仍能拿到完整记录。随仓 smoke 却仍在断言"正文里要看得见"。权威数据没丢,两边口径不一致,所以先报出来请维护者定夺,而不是我自己改一侧。
Activity
Weimr2627 commentedon Nov 5, 2026
Follow-up: onset pinned, consumer-side PR opened
The bisect closes the question this issue left open: the drop is an intentional
sqlite_v0change that landed without this consumer.41356265689(2026-11-01T22:16:06Z)41557935873(2026-11-03T01:10:15Z) and41740364791machine_section_projection.pyin that windowexamples/explore-todo-result-node-linkage-smoke.pyin that windowPositive control: the
filearm still renders the archived row inline and passes its inline assertion onmain, so the omission issqlite_v0-specific, not a general archive defect — consistent with the readback at:193-194returningexplore_result_node_refs == ["node_live", "node_dead"].I opened #8136 to reconcile the shipped smoke on the consumer side only: the
filearm keeps the inline assertion, thesqlitearm asserts the emitted pointer (archived_count=1plus the goal-scoped--include-archivedquery). Each new guard was poisoned once and all four poisons were caught. I am deliberately leaving this issue open instead ofCloses-ing it: if maintainers rule thatsqlite_v0should still render archived rows inline, that is a projection bug and the PR should be reverted rather than merged.