fix: wait for bounded receive scanning during sync pushes

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a1346b-72a4-7d40-b8bd-8b8ca346cfa2
This commit is contained in:
tegwick 2026-10-13 16:04:41 +02:00
parent 5830ba3c15
commit 7183f5993a
3 changed files with 85 additions and 1 deletions

View file

@ -36,6 +36,11 @@ from __future__ import annotations
import subprocess
# The admitted receive scanner has a 90-second total budget. Leave bounded
# headroom for transport and Git hooks; a timeout never proves remote refusal.
PUSH_TIMEOUT_SECONDS = 120
def pull_ff(repo_path: str) -> tuple[bool, str]:
"""Run ``git pull --ff-only`` on *repo_path*.
@ -66,11 +71,13 @@ def push_ff(repo_path: str) -> tuple[bool, str]:
try:
result = subprocess.run(
["git", "-C", repo_path, "push"],
capture_output=True, text=True, timeout=30,
capture_output=True, text=True, timeout=PUSH_TIMEOUT_SECONDS,
)
if result.returncode == 0:
return True, result.stdout.strip() or "pushed"
return False, result.stderr.strip() or "push failed"
except subprocess.TimeoutExpired:
return False, "push timed out; remote outcome unverified; inspect the remote ref before retrying"
except Exception as exc:
return False, str(exc)

View file

@ -0,0 +1,37 @@
"""Client deadlines must accommodate receive scanning without claiming timeout refusal."""
import subprocess
from pathlib import Path
import sys
sys.path.insert(0, str(Path(__file__).parent.parent / "scripts"))
import repo_sync as module
def test_push_budget_covers_admitted_scanner(monkeypatch, tmp_path):
observed = {}
def run(argv, **kwargs):
observed.update(argv=argv, **kwargs)
return subprocess.CompletedProcess(argv, 0, "", "")
monkeypatch.setattr(module.subprocess, "run", run)
ok, _ = module.push_ff(tmp_path)
assert ok
assert 90 < observed["timeout"] <= 180
assert "--force" not in observed["argv"]
def test_timeout_is_unverified_without_retry_or_child_output(monkeypatch, tmp_path):
calls = []
def run(argv, **kwargs):
calls.append(argv)
raise subprocess.TimeoutExpired(argv, kwargs["timeout"], output="private diagnostic fixture")
monkeypatch.setattr(module.subprocess, "run", run)
ok, message = module.push_ff(tmp_path)
assert not ok
assert "remote outcome unverified" in message
assert "inspect the remote ref" in message
assert "private diagnostic fixture" not in message
assert len(calls) == 1

View file

@ -0,0 +1,40 @@
---
id: STATE-WP-ADHOC-2026-10-13
type: workplan
title: "October 13 bounded sync compatibility fixes"
domain: infotech
repo: state-hub
status: finished
owner: codex
created: "2026-10-13"
updated: "2026-10-13"
flavor: implementation
---
## Allow admitted receive scanning to finish before timing out pushes
```task
id: STATE-WP-ADHOC-2026-10-13-T01
status: done
priority: high
```
CUST-WP-0080 found a normal source push accepted remotely after this client's
30-second deadline. The installed forge scanner has a 90-second total budget.
Raise only the push deadline to 120 seconds and label any timeout as an
unverified remote outcome; never infer rejection, retry automatically or allow
subsequent projection writes from that timeout. Repo Manager's 60-second push
path receives the same bounded fix under RMGR-WP-0021-T03.
Acceptance: ordinary acceptance/refusal and push-seal regressions, delayed real
receive hooks exceeding both old client budgets, a fixed value-free timeout
message with no retry, installed CLI source verification and owner projection.
Evidence is retained in Custodian's October 13 security evidence directory.
2026-10-13: 34 State Hub push-seal/deadline tests and 36 Repo Manager
deadline/historical/fast-projection tests pass. Both actual source helpers accept
a real 65-second receive hook, then preserve rejection and the unchanged remote
ref. The installed State Hub CLI module matches the reviewed source hash and
uses 120 seconds; Repo Manager imports its editable source. No residual remains
from this bounded compatibility fix. Broader scanner coverage stays in existing
CUST-WP-0080 and RMGR-WP-0021, not in this daily fix.