- Every cycle checks: wr status (daemon may transition to COMPLETED),
durable event log (find_matching_event), completion file (inotify)
- Removed debug print, relaxed test timing for inotify+disk I/O path
- All 11 ci_event_wait + 32 other wait tests green
ROOT CAUSE (Defect A, 9db239f + 51416aa deadline_pending->success):
ci_event_wait exited at deadline without releasing the daemon lease.
The orphaned lease blocked the daemon from writing resume tokens to
the FIFO for re-registered waits — so completion events that WERE
persisted (10:43:01 for 9db239f, 12:01:49 for 51416aa) could never be
delivered to a later waiter. Additionally: internal re-arms were
timer-blind (no durable-event recheck), and _fetch_runs used a single
50-run page (scheduled merge-robot floods push older SHAs past it).
FIXES:
- lease release in run() finally block (orphan prevention)
- durable-event recheck on every internal re-arm
- _fetch_runs paginates up to 4 pages, collecting all matches
- deploy_qualify --sha flag (explicit sha, env masked)
- model sha = hint; stored target wins on mismatch
- behavioral tests: terminal-before-deadline, nonterminal-never-returned
Defect A root cause: Gitea runs-list page flood (scheduled merge-robot
runs push relevant SHAs past the limit=50 first page) + collect-only-
first-page pagination -> terminal commit read as pending -> parked until
deadline. FIX: _fetch_runs paginates up to 4 pages collecting all matches
before verdict.
Defect B root cause: authority_verdict spawned deploy_qualify reading
DEPLOY_SHA from ambient env. FIX: explicit --sha arg (env masked when
sha is explicit); _ci_runs_verdict/op_ci_alive take sha as parameter
only; no env read remains in the authority path.
Defect C root cause: model sha treated as lookup key — a typo derived a
ghost operation. FIX: model sha is a HINT; unresolved sha + single
pending op -> stored target used with model_sha_mismatch logged; bound
op always wins over hints. deploy_qualify gained --sha flag (env kept
for workflow backward-compat only).
Tests: H-matrix (identity, prefix collision, env staleness,
monotonicity, aggregator lag, operation-id-first) + full 2179 suite.
Gitea's combined commit-status endpoint can 404 for the newest commit
(observed live on auto-version bump commits: status object materializes
late). When deploy_qualify returns pending AND the status endpoint is
unreadable, fall back to the operation-scoped Actions-runs verdict (same
evidence the two legs read). Also export DEPLOY_SHA in run() for python
callers. Found via E10 fresh-process proof.
- PendingOperation = durable continuation object: continuation_state
(ACTIVE_REASONING/WAITING_EXTERNAL/RESUMABLE/RECOVERY_REQUIRED),
canonical op_type/authority, task_id — parked cognition is a first-class
durable state a fresh process can read
- ci_event_wait stamps cognitive-state transitions (WAITING_EXTERNAL on
park, RESUMABLE/RECOVERY_REQUIRED on terminal)
- DEPLOY_SHA export fix: CLI/python run() consumers previously got a
silent 'pending' authority verdict forever — the authority subprocess
never received the sha (found via E10 fresh-process proof)
- await_intent_cli route-bash: Bash commands expressing external wait
intent compile to the canonical continuation (new bash.ts harness tool
routes through it); plain local sleeps execute normally
- tests/test_await_intent.py: E-matrix (derivation truth table,
provenance order, observability)
- event_wait.find_matching_event(): replays matching completion events
from the durable bridge event log at registration. Root-caused from
TWO production cycles: on a serialized single-runner machine the CI
wake always lands before/around deploy registration — a forward-only
FIFO rendezvous can never deliver it (both cycles fell back to the
900s deadline, truthfully). The event log exists precisely for this;
the wake is still never the verdict.
- ci_event_wait: event_replayed mode short-circuits to the authority
read; 2 new held-outs (9 total).
- drift_resume.py (16P): claim-vs-observation reconciliation with
EXPECTED/BENIGN/MATERIAL/CONFLICTING/UNKNOWN classes; MATERIAL/
CONFLICTING/UNKNOWN block dependent work; user-locked claims escalate
to CONFLICTING (reality never silently overrides user-locked
authority). Held-outs driven by the REAL 16O fixture: the VAT
regression blocks resume; the checkpoint commit resumes clean.
- 16O benchmark persisted (store/evidence/t16/16O_benchmark.md): honest
result — on a tiny fixture cold and scaffold-assisted re-entry cost
about the same (8 vs 9 files); the scaffold's advantage is drift
classification, recorded next actions, and intent, not raw step
count. No fabricated win.
Suite 1884 green; ratchets PASS.
- deploy.yml sleep-30 polling loop REPLACED: registers a gitea-identity
PROCESS_EVENT wait, yields in select() on the FIFO, resumes on the
ci.yml notify-event-bridge WAKE, then re-reads the canonical Gitea
verdict (deploy_qualify.py). Event payload is never completion truth.
- ci.yml gains notify-event-bridge (always(), best-effort): a red CI
wakes the waiter as loudly as a green one; bridge unreachable ->
watchdog recovery covers the lost wake.
- event_wait.py: register_process_wait gains provider/event_type/sha
identity (16E: ONE bridge primitive; builder + gitea are adapters);
open_fifo_reader + caller-owned fifo_fd close the 16Y#10 race (event
before waiter in select()); await_resume_event returns eof instead of
busy-looping on a caller-owned fd.
- ci_event_wait.py watchdog: failure DETECTOR only — liveness-gated
re-arm, one-shot authority recovery on lost events, truthful failure
when no verdict exists; timestamps emitted for the 16D latency proof.
- tests: 8 held-outs on the REAL daemon (shared wr_daemon fixture in
conftest — no duplicated helpers). Daemon-side: /process-event passes
through provider/event_type/sha (defaults preserve T15); lease_path
sanitizes slash-bearing session ids (resume delivery was impossible
for them — found live, fixed in daemon snapshot 79434e0).
Suite 1861 green; ratchets PASS; Henxels rc=0.