STATE-WP-0070: identity headers, archive 0069, phase-2 workplan
Add X-StateHub-Component to fix-consistency and other State Hub REST callers for legacy-meter attribution. Archive STATE-WP-0069; open STATE-WP-0070 for meter-gated phase-2 retirement. Task POST bodies use workplan_id only.
This commit is contained in:
parent
2f06751d4f
commit
bb6bec9f10
10 changed files with 198 additions and 17 deletions
|
|
@ -32,13 +32,15 @@ except Exception: # pragma: no cover — event publishing is optional
|
|||
publish_event = None # type: ignore[assignment]
|
||||
shutdown_publisher = None # type: ignore[assignment]
|
||||
|
||||
API = "http://127.0.0.1:8000"
|
||||
API = os.environ.get("API_BASE", "http://127.0.0.1:8000").rstrip("/")
|
||||
_LEGACY_METER_HEADERS = {"X-StateHub-Component": "state-hub.cleanup-stale-tasks"}
|
||||
STALE_STATUSES = set(OPEN_TASK_STATUSES)
|
||||
CLOSED_WS_STATUS = set(CLOSED_WORKSTREAM_STATUSES)
|
||||
|
||||
|
||||
def get(path: str) -> list | dict:
|
||||
with urllib.request.urlopen(f"{API}{path}") as r:
|
||||
req = urllib.request.Request(f"{API}{path}", headers=_LEGACY_METER_HEADERS)
|
||||
with urllib.request.urlopen(req) as r:
|
||||
return json.loads(r.read())
|
||||
|
||||
|
||||
|
|
@ -49,7 +51,7 @@ def _request(method: str, url: str, payload: dict) -> dict:
|
|||
req = urllib.request.Request(
|
||||
url,
|
||||
data=data,
|
||||
headers={"Content-Type": "application/json"},
|
||||
headers={"Content-Type": "application/json", **_LEGACY_METER_HEADERS},
|
||||
method=method,
|
||||
)
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -122,6 +122,13 @@ except ImportError:
|
|||
# Constants
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_LEGACY_METER_COMPONENT = "state-hub.fix-consistency"
|
||||
|
||||
|
||||
def _legacy_meter_headers() -> dict[str, str]:
|
||||
return {"X-StateHub-Component": _LEGACY_METER_COMPONENT}
|
||||
|
||||
|
||||
_TASK_BLOCK_RE = re.compile(r"```task\s*\n(.*?)\n```", re.DOTALL)
|
||||
_HEADING_RE = re.compile(r"^(#{1,4})\s+(.+?)$", re.MULTILINE)
|
||||
_ARCHIVED_WP_RE = re.compile(r"^\d{6}-(.+\.md)$")
|
||||
|
|
@ -566,7 +573,12 @@ def _api_get(
|
|||
last_error: Exception | None = None
|
||||
for attempt in range(_API_GET_RETRIES):
|
||||
try:
|
||||
with _httpx.Client(base_url=api_base, timeout=10.0, follow_redirects=True) as c:
|
||||
with _httpx.Client(
|
||||
base_url=api_base,
|
||||
timeout=10.0,
|
||||
follow_redirects=True,
|
||||
headers=_legacy_meter_headers(),
|
||||
) as c:
|
||||
r = c.get(path, params=filtered if filtered else None)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
|
@ -604,7 +616,12 @@ def _api_patch(api_base: str, path: str, body: dict) -> Any:
|
|||
if not path.endswith("/"):
|
||||
path += "/"
|
||||
try:
|
||||
with _httpx.Client(base_url=api_base, timeout=10.0, follow_redirects=True) as c:
|
||||
with _httpx.Client(
|
||||
base_url=api_base,
|
||||
timeout=10.0,
|
||||
follow_redirects=True,
|
||||
headers=_legacy_meter_headers(),
|
||||
) as c:
|
||||
r = c.patch(path, json=body)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
|
@ -620,7 +637,12 @@ def _api_put(api_base: str, path: str, body: dict) -> Any:
|
|||
if not path.endswith("/"):
|
||||
path += "/"
|
||||
try:
|
||||
with _httpx.Client(base_url=api_base, timeout=30.0, follow_redirects=True) as c:
|
||||
with _httpx.Client(
|
||||
base_url=api_base,
|
||||
timeout=30.0,
|
||||
follow_redirects=True,
|
||||
headers=_legacy_meter_headers(),
|
||||
) as c:
|
||||
r = c.put(path, json=body)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
|
@ -634,7 +656,12 @@ def _api_post(api_base: str, path: str, body: dict) -> Any:
|
|||
if not path.endswith("/"):
|
||||
path += "/"
|
||||
try:
|
||||
with _httpx.Client(base_url=api_base, timeout=10.0, follow_redirects=True) as c:
|
||||
with _httpx.Client(
|
||||
base_url=api_base,
|
||||
timeout=10.0,
|
||||
follow_redirects=True,
|
||||
headers=_legacy_meter_headers(),
|
||||
) as c:
|
||||
r = c.post(path, json=body)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
|
@ -2461,7 +2488,7 @@ def fix_repo(
|
|||
if t_priority not in VALID_TASK_PRIORITIES:
|
||||
t_priority = "medium"
|
||||
t_data = _api_post(api_base, "/tasks", {
|
||||
"workstream_id": new_ws_id,
|
||||
"workplan_id": new_ws_id,
|
||||
"title": str(task.get("title", t_id)).strip() or t_id,
|
||||
"description": task.get("description") or None,
|
||||
"status": t_status,
|
||||
|
|
@ -2545,7 +2572,7 @@ def fix_repo(
|
|||
if t_priority not in VALID_TASK_PRIORITIES:
|
||||
t_priority = "medium"
|
||||
t_data = _api_post(api_base, "/tasks", {
|
||||
"workstream_id": ws_id,
|
||||
"workplan_id": ws_id,
|
||||
"title": str(task.get("title", t_id)).strip() or t_id,
|
||||
"description": task.get("description") or None,
|
||||
"status": t_status,
|
||||
|
|
|
|||
|
|
@ -301,13 +301,22 @@ def check_files(workplans_dir: Path, report: Report) -> list[dict]:
|
|||
# State-hub API checks
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _legacy_meter_headers() -> dict[str, str]:
|
||||
return {"X-StateHub-Component": "state-hub.validate-repo-adr"}
|
||||
|
||||
|
||||
def _api_get(api_base: str, path: str, params: dict | None = None) -> Any:
|
||||
if not _HAS_HTTPX:
|
||||
return None
|
||||
if not path.endswith("/"):
|
||||
path += "/"
|
||||
try:
|
||||
with _httpx.Client(base_url=api_base, timeout=10.0, follow_redirects=True) as c:
|
||||
with _httpx.Client(
|
||||
base_url=api_base,
|
||||
timeout=10.0,
|
||||
follow_redirects=True,
|
||||
headers=_legacy_meter_headers(),
|
||||
) as c:
|
||||
r = c.get(path, params={k: v for k, v in (params or {}).items() if v is not None})
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue