feat: recover interrupted Human Gate decisions (Closes #1446)
CI / lint (pull_request) Successful in 3m56s
CI / build-release (pull_request) Successful in 7s
CI / browser-journey (pull_request) Failing after 7m20s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy committed 2026-08-26 22:10:01 +00:00
1 parent 60f140d26a
commit b303683ba1
21 files changed
+251 -58

No files matched your search

+29 -3
View File
@@ -29,7 +29,7 @@ def test_release_artifact_reopens_human_gates_with_one_fresh_mobile_snapshot(
current = {"gate": "g1"}
evidence_url = {"value": "/evidence/manifest"}
list_requests: list[str] = []
decision_requests: list[str] = []
decision_requests: list[dict] = []
browser_errors: list[str] = []
def gate(gate_id: str) -> dict:
@@ -62,7 +62,14 @@ def test_release_artifact_reopens_human_gates_with_one_fresh_mobile_snapshot(
def human_gates_route(route):
path = route.request.url.split("?", 1)[0]
if route.request.method == "POST":
decision_requests.append(path)
decision_requests.append({
"path": path,
"key": route.request.headers.get("idempotency-key"),
"body": route.request.post_data_json,
})
if len(decision_requests) == 1:
route.abort("failed")
return
payload = {"receipt_id": "receipt-1", "state": "released"}
elif path.endswith("/api/v1/human-gates"):
list_requests.append(current["gate"])
@@ -131,9 +138,28 @@ def test_release_artifact_reopens_human_gates_with_one_fresh_mobile_snapshot(
assert progress_key and progress_key.endswith(":g1:1")
assert page.evaluate("key => localStorage.getItem(key) !== null", progress_key)
page.locator('[data-gate-decision="release"]').click()
expect(page.locator("#human-gate-detail")).to_contain_text("Decision outcome unknown")
expect(page.locator("[data-gate-recover]")).to_have_count(1)
decision_key = page.evaluate(
"Object.keys(localStorage).find(key => key.startsWith('stackchain.human-gate-decision.v1:'))"
)
assert decision_key
assert len(decision_requests) == 1
page.reload(wait_until="networkidle")
page.evaluate("document.querySelector('#open-human-gates').click()")
expect(page.locator("#human-gate-detail")).to_contain_text("Decision outcome unknown")
recover = page.locator("[data-gate-recover]")
recover.scroll_into_view_if_needed()
expect(recover).to_be_visible()
recover_bounds = recover.bounding_box()
assert recover_bounds and recover_bounds["height"] >= 44
recover.click()
expect(page.locator("#human-gates-status")).to_contain_text("Decision saved")
expect(page.locator(".human-gate-decision-tray")).to_have_count(0)
assert len(decision_requests) == 1
assert len(decision_requests) == 2
assert decision_requests[0] == decision_requests[1]
assert not page.evaluate("key => localStorage.getItem(key) !== null", decision_key)
assert not page.evaluate("key => localStorage.getItem(key) !== null", progress_key)
page.evaluate("document.querySelector('#close-human-gates').click()")