Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

[Bug]: quota gate authorizes automatic turns for a Goal whose declared active state file is missing

Đang mở
#6,799 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

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
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
python
Lĩnh vực
backend, testing

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

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. 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.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của loopx-project/loopx

Tất cả issue của loopx-project/loopx

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.