Implement worker coordination runtime and finish WP-0003
All checks were successful
check / test (push) Successful in 7m8s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a07b5b-ea58-7ad2-bdbb-0b1c995cfc35
This commit is contained in:
tegwick 2026-09-07 23:19:52 +02:00
parent 214964ccb8
commit 628f984a10
23 changed files with 3025 additions and 544 deletions

View file

@ -0,0 +1,168 @@
import hashlib
import json
import math
import os
from dataclasses import asdict, dataclass, field
from pathlib import Path
from urllib.parse import urlsplit
import tomllib
@dataclass
class Config:
state_dir: Path = field(
default_factory=lambda: Path(
os.environ.get(
"COORDINATION_STATE_DIR",
str(
Path(os.environ.get("XDG_STATE_HOME", Path.home() / ".local/state"))
/ "coordination-engine"
),
)
)
)
socket: Path = field(
default_factory=lambda: Path(
os.environ.get(
"COORDINATION_SOCKET",
str(
Path(
os.environ.get(
"XDG_RUNTIME_DIR", f"/tmp/coordination-{os.getuid()}"
)
)
/ "coordination-engine.sock"
),
)
)
)
tamq_socket: Path = field(
default_factory=lambda: Path(
os.environ.get(
"TAMQ_SOCKET",
str(Path(os.environ.get("XDG_RUNTIME_DIR", "/tmp")) / "tamq.sock"),
)
)
)
api_base: str = field(
default_factory=lambda: os.environ.get(
"STATEHUB_API_BASE", "http://127.0.0.1:8000"
)
)
repos: list[str] = field(default_factory=list)
endpoints: dict[str, str] = field(default_factory=dict)
poll_interval: float = 15
lease_seconds: float = 30
renew_interval: float = 10
timeout: float = 5
busy_timeout: float = 5
max_attempts: int = 4
retry_backoff: list[float] = field(default_factory=lambda: [5, 15, 60, 300])
policy_profile: str = "default"
# Only these classes may be requested automatically. Unknown classes stop.
allow: list[str] = field(
default_factory=lambda: [
"repo_inspect",
"repo_edit",
"local_checks",
"state_updates",
"tmux_wake",
]
)
def validate(self):
for key in (
"poll_interval",
"lease_seconds",
"renew_interval",
"timeout",
"busy_timeout",
):
value = getattr(self, key)
if (
isinstance(value, bool)
or not isinstance(value, (float, int))
or not math.isfinite(value)
or value <= 0
):
raise ValueError(f"invalid {key}")
if self.renew_interval >= self.lease_seconds:
raise ValueError("renew_interval must be shorter than lease_seconds")
if type(self.max_attempts) is not int or not 0 <= self.max_attempts <= 9:
raise ValueError("max_attempts must be 0..9")
if not self.retry_backoff or any(
type(v) not in (int, float) or not math.isfinite(v) or v <= 0
for v in self.retry_backoff
):
raise ValueError("retry_backoff must contain positive finite delays")
if self.policy_profile != "default" or not set(self.allow) <= {
"repo_inspect",
"repo_edit",
"local_checks",
"state_updates",
"tmux_wake",
}:
raise ValueError("unsupported policy profile or action grant")
if not isinstance(self.repos, list) or any(
not isinstance(r, str)
or not r
or any(
c
not in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._"
for c in r
)
for r in self.repos
):
raise ValueError("repos must contain exact repository slugs")
if not isinstance(self.endpoints, dict) or any(
k not in self.repos or not isinstance(v, str) or not v
for k, v in self.endpoints.items()
):
raise ValueError("endpoints must map configured repos to endpoint IDs")
url = urlsplit(self.api_base)
if (
url.scheme not in {"http", "https"}
or not url.hostname
or url.username
or url.password
or url.query
or url.fragment
):
raise ValueError("invalid State Hub URL; credentials are not configuration")
for name in ("state_dir", "socket", "tamq_socket"):
setattr(self, name, Path(getattr(self, name)).expanduser().absolute())
return self
@property
def version(self):
return hashlib.sha256(
json.dumps(asdict(self), default=str, sort_keys=True).encode()
).hexdigest()[:16]
@classmethod
def load(cls, path=None):
path = Path(
path
or os.environ.get(
"COORDINATION_CONFIG",
str(
Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config"))
/ "coordination-engine/config.toml"
),
)
)
data = (
tomllib.loads(path.read_text()).get("coordination", {})
if path.exists()
else {}
)
for env, key in [
("COORDINATION_STATE_DIR", "state_dir"),
("COORDINATION_SOCKET", "socket"),
("TAMQ_SOCKET", "tamq_socket"),
("STATEHUB_API_BASE", "api_base"),
]:
if env in os.environ:
data[key] = os.environ[env]
return cls(**data).validate()