[Bug]: quota gate authorizes automatic turns for a Goal whose declared active state file is missing
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 75/100
Hướng nghiên cứu
Start with goal_status_health_ok in loopx/control_plane/quota/decision_summary.py, then trace how per-goal findings are represented in the status contract and compare with docs/status-data-contract.md so the deliberately shadowed source-registry findings remain non-blocking. Reproduce with the issue's bootstrap, state-file deletion, status, and quota should-run commands. Done when a missing-state finding makes quota fail closed with that finding as the reason, while the shadowed findings still do not block.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
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
Observed or reproduced in a real environment
LoopX version or commit
a54c030ee79ea9270fed4ca94f9592f32a19232a (current main, LoopX 2.0.0a1)
Host or runtime surface
Not host-specific
LoopX area
Control plane (goals, todos, quota, scheduler, registry, runtime)
Problem
The quota gate authorizes an automatic turn for a Goal whose declared active state file is missing.
loopx status already knows this state. It emits a global-registry finding
kind=state_file_missing, severity=action with the recommended action
reconnect / preview loopx retire-global-goal, and lifts it into the attention
queue. But the same status also projects the Goal as
connected_without_run with recommended_action=run the first read-only adapter tick, and the quota gate follows that lane:
loopx quota should-run --goal-id <id> returns status_health_ok=true,
decision=run, should_run=true, normal_delivery_allowed=true,
interaction_contract.agent_channel.must_attempt=true, and a required_reads
entry that runs cat against the missing ACTIVE_GOAL_STATE.md.
loopx/control_plane/quota/decision_summary.py::goal_status_health_ok is the
guard that is supposed to keep this fail closed. Today it fails only when
global_registry.ok is False or the status contract reports an error for the
Goal; it never reads the per-goal state_file_missing finding. The finding is
not one of the source-registry provenance shadows that
docs/status-data-contract.md deliberately collapses into the live quota item,
so nothing suppresses it.
Who is harmed and how much. Any owner of an automatic host loop (Codex App
heartbeat, Claude Code /loop, generic host schedulers) whose Goal outlives its
active state file: a renamed or moved project, a removed agent worktree, a
deleted scratch checkout, or an interrupted state write. The machine-wide
registry intentionally keeps such Goals — that is why
loopx retire-global-goal and the state_file_missing finding exist — so the
condition is a supported operational state, not corruption. Every automation
cadence then authorizes and obligates a model turn against a Goal with no
readable state. At the documented initial App automation cadence
(app_automation_initial_rrule = FREQ=MINUTELY;INTERVAL=30 in
docs/quota-allocation.md) that is up to 48 authorized turns per day for one
stale entry. The turn cannot advance the Goal and cannot clear the finding,
and the same should_run=true decision is returned next time, so the loop keeps
spending turns until a human notices and retires the entry. The documented
repair action (reconnect or retire) is never selected because the authoritative
gate says run. The defect is host-independent; the quota decision is the same
on Linux, macOS and Windows.
Minimal reproduction
From a source checkout of a54c030ee79ea9270fed4ca94f9592f32a19232a on any
platform; <tmp> is a fresh directory:
loopx bootstrap --project <tmp> --goal-id state-gone --objective "reproduce missing state"
rm <tmp>/.loopx/goals/state-gone/ACTIVE_GOAL_STATE.md
loopx --format json status
# finding: kind=state_file_missing, severity=action,
# recommended_action="reconnect ... or preview loopx retire-global-goal"
loopx --format json quota should-run --goal-id state-gone --runtime-profile generic_cli
Observed:
{"status_health_ok": true, "decision": "run", "should_run": true,
"normal_delivery_allowed": true, "state": "eligible",
"recommended_action": "run the first read-only adapter tick and save a compact run record"}
with interaction_contract.agent_channel.must_attempt=true and
required_reads[0].command pointing at the deleted
.loopx/goals/state-gone/ACTIVE_GOAL_STATE.md. Deleting the whole project
directory instead of only the state file produces the same decision.
Expected behavior
The quota gate refuses automatic compute for a Goal whose declared active state
file is missing, matching the status finding and its recommended repair action:
status_health_ok=false, should_run=false, normal_delivery_allowed=false,
with the missing-state finding named as the reason. A host automation then
surfaces the repair/retire action instead of spending a turn on an unreadable
Goal.
Actual behavior
should_run=true with normal delivery allowed and an unreadable required read.
The same status payload simultaneously recommends retiring the Goal, so the
two control-plane surfaces contradict each other and the quota gate wins.
Sanitized diagnostics
$ loopx --format json status | jq '.global_registry.findings[]
| select(.goal_id=="state-gone")'
{"kind":"state_file_missing","severity":"action",
"message":"`state-gone` active state file is missing",
"recommended_action":"preview `loopx retire-global-goal --goal-id state-gone`; ...",
"goal_id":"state-gone"}
$ loopx --format json quota should-run --goal-id state-gone --runtime-profile generic_cli \
| jq '{status_health_ok, decision, should_run, normal_delivery_allowed, state}'
{"status_health_ok":true,"decision":"run","should_run":true,
"normal_delivery_allowed":true,"state":"eligible"}
Additional context
The narrowest owner is goal_status_health_ok in
loopx/control_plane/quota/decision_summary.py: it already gates quota on
status/contract health, so consulting the per-goal state_file_missing finding
there keeps the decision fail closed without reinterpreting the attention queue.
source_registry_missing / stale_source_registry are deliberately shadowed
by docs/status-data-contract.md and should not be made blockers.
- Ngôn ngữ chính
- Python
- Star
- 6.2k
- Fork
- 596
- Merge trung bình
- 6 giờ 44 phút
- Pull request đã merge (30 ngày)
- 915
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của loopx-project/loopx
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
loopx-project/loopx#6842 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
loopx-project/loopx#6108 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
loopx-project/loopx#5688 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 60/100
loopx-project/loopx#5632 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
loopx-project/loopx#5443 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của loopx-project/loopx
Issue tương tự
-
documentation good first issue
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
selimfirat/pysad#379 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
open-webui/open-webui#32805 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
fix: [bug description] HTML CVE metric table shows only the last CVE for each productCó thể đã có người làm @Chris-wh233 đã nhận hôm nay. Đang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 66/100
ossf/cve-bin-tool#5976 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
needs-triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
gke-labs/kube-agents#3615 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
deferred
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
Maintainer thường phản hồi trong vòng 1 ngày