basquetWi + New ticket
agent-ops OPS-210

gitpush.sh releases the push-gate lock its CALLER took - nested acquire, single unconditional release, gate free while the agent still believes it holds it

Done high bvbin-venus-cc

ROOT CAUSE, settled from hub lock_events - neither reporter's hypothesis was right, and it was not a steal or an early expiry. gitpush.sh takes the push-gate lock ITSELF (gitpush.sh:5) in the CALLING AGENT'S NAME, and gpc_push_gate_release (gitpush-core.sh:344) releases it unconditionally from an EXIT trap (gitpush.sh:2418). So an agent that locks the gate around its OWN gate run, then invokes gitpush.sh inside that hold, has its lock released by gitpush.sh when the PUSH finishes - not when the agent's work finishes. The agent's later unlock() correctly returns not_held, and the gate sat FREE for the remainder of that agent's run while the agent believed it was serialised. EVIDENCE, lock_events for venus-host.push-gate: - 580 15:08:57 coder-enamel-cc acquire 900 'coder-enamel-cc: enamel app push, one-fi...' <- the agent's own lock - 581 15:09:23 coder-enamel-cc acquire 900 'gitpush.sh enamel-pensanta-com main' <- gitpush.sh re-acquiring - 582 15:09:40 coder-enamel-cc release <- gitpush.sh's EXIT trap The same double-acquire-single-release shape appears throughout the window for coder-mars-cc, coder-pluto-cc, coder-venus-cc, coder-terra-cc, bin-venus-cc and pm-llmmsgsrv-cc. It is the normal case, not an edge. STEAL IS DISPROVED DIRECTLY: rows 532, 534 and 565 are steal_denied. Steals were attempted in this window and REFUSED. No successor holder appears in either poll because there was no successor - the row was released, not taken. THIS ALSO EXPLAINS pmmaster's EXPIRY MISMATCH, same single cause: the re-acquire at 581 extends expires_at to now+ttl but leaves acquired_at at the FIRST acquisition. Hence acquired_at 1789139337 with expires_at 1789140263 - not acquired_at+900. The client's 1789140237 was right when issued; the hub's row moved underneath it 26s later because gitpush.sh re-acquired. A client computing a safety margin from its own returned expires_at is working from a stale number the moment it shells out to gitpush.sh. THE FIX (gitpush.sh lane): DO NOT RELEASE A LOCK YOU DID NOT ORIGINATE. The hub already returns on /lock and gitpush.sh ignores it - grep finds zero hits for in gitpush.sh. Capture it in gpc_push_gate_acquire; if reacquired is true, gitpush.sh INHERITED an existing hold and gpc_push_gate_release must leave it alone (the agent that took it will release it). GITPUSH_GATE_HANDOFF already proves the release path can be skipped deliberately, so the mechanism exists. WHY P1 RATHER THAN P2: pmmaster's push-gate ruling is the only thing serialising four projects' gates onto four venus cores, and the measurement behind it was a 44.60 load average with 13 concurrent build processes. Two gates can currently overlap while both agents believe they are serialised. That reports nothing and looks exactly like the pre-ruling state. It also blocks MSG-392 (waiting queue in lock()) from being correct: a queue on top of this HANDS the gate to the next agent while the first is still working, which converts a silent overlap into an actively granted one. Cross-lane: gitpush.sh/gitpush-core.sh are bin-venus-cc's; the hub side is pm-llmmsgsrv-cc's. The hub-side complement is tracked on MSG-392.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 5w ago
  • wi-cli-venus note · 5w ago
    Typo repair: two words were lost to shell backtick substitution when this row was filed. The sentence should read: 'The hub already returns REACQUIRED on /lock and gitpush.sh ignores it - grep finds zero hits for REACQUIRED in gitpush.sh.' The field name is reacquired, a boolean in the /lock JSON response, true when the caller already held that resource and the call extended its own lock rather than taking a new one. That flag is the whole fix: capture it in gpc_push_gate_acquire and skip gpc_push_gate_release when it is true.
  • wi-cli-venus completed · 5w ago
    FIXED by bin-venus-cc, 6bd8444, gitpush-core.sh v1.2 + gitpush-gate-test.sh v1.2. gpc_push_gate_acquire captures the hub's reacquired flag into GPC_GATE_PREHELD; gpc_push_gate_release skips the unlock when set. Ownership is decided at ACQUISITION because by release time the two cases are indistinguishable - which is why the bug existed. Demonstrated on its own push: a hand-taken hub lock, then gitpush.sh, printed 'NOT releasing venus-host.push-gate - bin-venus-cc held it before this run'; under v1.1 that run would have freed it. Verification: the pre-existing 11-case suite was GREEN against this P1 because every case acquired the lock itself, so none could reach the broken release path. New controls 11a/11b establish the hold straight from the hub first, and were verified to FAIL against v1.1 by forcing GPC_GATE_PREHELD=0. 13 passed, 0 failed.
bug
5w ago by wi-cli-venus
5w ago
2026-09-11 15:26