Complete tasks 3-7: harden verdict parsing, outputs retention, base branch, linux schedule parity, claim loop task
CI / build (push) Has been cancelled
CI / build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
# Bug Report: add-state-loop-lock
|
||||
|
||||
Bug_find phase observations. Each observation is non-blocking unless marked BLOCKER.
|
||||
|
||||
## O1 — `print(... state['resumed_count'] ...)` after `with _loop_lock` exits, status.py:cmd_approve_loop
|
||||
|
||||
`cmd_approve_loop` references `state['resumed_count']` AFTER the `with`
|
||||
block exits. `state` is in function scope and was assigned inside the with
|
||||
block; the value is the post-mutation dict. **Not a bug** — confirmed by
|
||||
tracing the variable lifecycle. Safe.
|
||||
|
||||
## O2 — `_disable_schedule` / `_enable_schedule` left OUTSIDE the lock for pause/resume/approve; INSIDE for halt
|
||||
|
||||
For `cmd_pause_loop` / `cmd_resume_loop` / `cmd_approve_loop`,
|
||||
`_disable_schedule` / `_enable_schedule` is called AFTER the `with
|
||||
_loop_lock` block exits (line ~1950 area, after the lock releases).
|
||||
For `cmd_check_gate`'s `_halt_loop` call, `_disable_schedule` is called
|
||||
INSIDE the lock (since `_halt_loop` couples the halt-write with the
|
||||
schedule disable).
|
||||
|
||||
**Transient**: between the loop's `.state.loop` write (inside the lock)
|
||||
and the subsequent OS schedule unit disable (outside the lock), the OS
|
||||
scheduler could fire another tick. That tick's `_gate` subprocess reads
|
||||
`status=paused` and exits 0 (clean scheduler self-skip). So no real
|
||||
over-tick — just a no-op tick for ~100ms. Same for resume/approve.
|
||||
|
||||
**Not a bug** — documented behavior; matches SPEC R4 (idempotence inside
|
||||
the lock scope; OS-level schedule toggles are out-of-band best-effort).
|
||||
The transient inconsistency is harmless because `--check-gate` already
|
||||
self-skips on non-running.
|
||||
|
||||
## O3 — `_gate` subprocess acquires status.py's `_loop_lock`, honors env-var bypass
|
||||
|
||||
If a future caller of `status.py --check-gate` manually sets
|
||||
`$AUTOMATON_NO_LOOP_LOCK=1` in their shell, `_loop_lock` becomes a no-op
|
||||
even when invoked standalone. **Not a bug**: the env var is a documented
|
||||
escape hatch; a manual user who sets it accepts that the lock is bypassed.
|
||||
The runner's own subprocess env is private to the subprocess (passed via
|
||||
the `env` kwarg to `subprocess.run` in `_run_json` invoked from `_gate`).
|
||||
The harness subprocesses do NOT inherit the var (verified: `subprocess.run`
|
||||
without `env` inherits `os.environ`, which is unmodified at runner top
|
||||
level).
|
||||
|
||||
Risk assessment: HIGH only if a user wraps `status.py` invocations with
|
||||
`AUTOMATON_NO_LOOP_LOCK=1` AND expects pause-loop / approve-loop /
|
||||
check-gate invocations to serialize. Documented in `_loop_lock`'s
|
||||
docstring. **Not a bug** — escape hatch has explicit semver-stable
|
||||
contract.
|
||||
|
||||
## O4 — `_loop_lock` is non-re-entrant across processes
|
||||
|
||||
POSIX `flock` is per-fd-per-process: a second process blocks cleanly
|
||||
waiting for the first to release. POSIX `flock` IS re-entrant within a
|
||||
single process on a single fd. Windows `msvcrt.locking` is NOT re-entrant
|
||||
within a single process (would deadlock on re-acquire). Documented in
|
||||
`_loop_lock`'s docstring.
|
||||
|
||||
Audit shows no nested `_loop_lock` callsites. **Not a bug** — explicitly
|
||||
forbidden by the SPEC ("Audit every callsite to ensure no nested
|
||||
`_loop_lock` within the same `with` block"). Audited in
|
||||
IMPLEMENTATION.md's "NESTED-LOCK AUDIT" section.
|
||||
|
||||
## O5 — `cmd_tick`'s lock scope includes the entire harness subprocess run
|
||||
|
||||
The runner holds `_loop_lock` across the long-running
|
||||
Implement/Verify/Orchestrate harness subprocesses. A concurrent
|
||||
`--pause-loop` invoked by an operator will block for the WHOLE tick
|
||||
duration (potentially minutes). The harness is unaware of `_loop_lock`
|
||||
and cannot signal the operator to wait gracefully.
|
||||
|
||||
**Documented behavior** per SPEC D-L1: "ticks short; operator notices
|
||||
via `--loop-list` stale `last_tick_at`". If ticks grow long, future
|
||||
work could split the lock into a short gate-decision lock and a longer
|
||||
state-mutation lock. **Not a bug** — explicit v1.1 scope per
|
||||
`design/loops/BACKLOG.md` (out of scope for this task).
|
||||
|
||||
## Verdict
|
||||
|
||||
No BLOCKERS. All observations are documented behaviors per SPEC + D-L6.
|
||||
Recommend proceeding to adversarial_bug_find.
|
||||
Reference in New Issue
Block a user