Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4220621cb0 | ||
|
|
4b54451444 | ||
|
|
962e3511e1 | ||
|
|
fb809135c6 | ||
|
|
10acdfe708 | ||
|
|
fd9e1bffb8 | ||
|
|
631426763e | ||
|
|
09cd18ad54 | ||
|
|
da500df487 | ||
|
|
51416aa95e | ||
|
|
b68f31ff0d | ||
|
|
dd41f15571 | ||
|
|
57e4b8672c | ||
|
|
6923128f45 | ||
|
|
9db239fcb4 | ||
|
|
658ec63627 | ||
|
|
427c3ac6bb | ||
|
|
509ec00c87 |
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# Rune
|
||||
|
||||
**Current release: v0.85.4**
|
||||
**Current release: v0.85.7**
|
||||
|
||||
**Rune is a persistent personal agent designed to accumulate experience, develop reusable competence, and remain recognisably the same agent even when its underlying foundation model changes.**
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "rune"
|
||||
version = "0.85.4"
|
||||
version = "0.85.7"
|
||||
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv pip compile pyproject.toml -o /tmp/regen2.txt --extra dev --extra memory --python-version 3.11
|
||||
# uv pip compile pyproject.toml -o /tmp/req3.txt --extra dev --extra memory --python-version 3.11
|
||||
aiohappyeyeballs==2.7.1
|
||||
# via aiohttp
|
||||
aiohttp==3.14.3
|
||||
@@ -56,7 +56,7 @@ mdit-py-plugins==0.6.1
|
||||
# via textual
|
||||
mdurl==0.1.2
|
||||
# via markdown-it-py
|
||||
multidict==6.8.0
|
||||
multidict==6.9.0
|
||||
# via
|
||||
# aiohttp
|
||||
# yarl
|
||||
|
||||
@@ -328,6 +328,20 @@ def run(*, sha: str, deadline_secs: int,
|
||||
# python-level run() callers (tool normalization flow) must export it.
|
||||
if sha and not os.environ.get("DEPLOY_SHA"):
|
||||
os.environ["DEPLOY_SHA"] = sha
|
||||
# H-PATCH: resolve short SHAs to full 40-char — _fetch_runs and
|
||||
# deploy_qualify match on the FULL sha; a 12-char prefix would
|
||||
# silently fail equality and park the waiter until deadline
|
||||
# (the 962e351 root cause).
|
||||
if sha and len(sha) < 40:
|
||||
try:
|
||||
full = subprocess.run(
|
||||
["git", "-C", str(_SCRIPT_DIR.parent), "rev-parse", sha],
|
||||
capture_output=True, text=True, timeout=10)
|
||||
if full.returncode == 0:
|
||||
sha = full.stdout.strip()
|
||||
os.environ["DEPLOY_SHA"] = sha
|
||||
except (OSError, subprocess.TimeoutExpired):
|
||||
pass
|
||||
t0 = time.time()
|
||||
# §16Y #10 race fix: the FIFO reader exists BEFORE registration, so a
|
||||
# wake arriving in the registration window can always be delivered.
|
||||
@@ -434,6 +448,22 @@ def run(*, sha: str, deadline_secs: int,
|
||||
rearm_count += 1
|
||||
rearm_reason = "eof without token; durable record pending"
|
||||
continue
|
||||
# H-PATCH: re-check the durable event log on each re-arm —
|
||||
# the completion event may have arrived while the waiter was
|
||||
# between await_resume_event cycles (the 9db239f/51416aa root
|
||||
# cause). This makes internal re-arms event-aware, not
|
||||
# timer-blind.
|
||||
prior_event = ew.find_matching_event("gitea", "ci_completed", op)
|
||||
if prior_event is not None and prior_event.get("exit_code") is not None:
|
||||
event_at = event_at or time.strftime(
|
||||
"%Y-%m-%dT%H:%M:%SZ", time.gmtime())
|
||||
resumed_at = time.strftime(
|
||||
"%Y-%m-%dT%H:%M:%SZ", time.gmtime())
|
||||
verdict = normalize_verdict(
|
||||
authority_after_wake(op_type, sha))
|
||||
if verdict != "pending":
|
||||
mode = "event_recovered_from_durable_record"
|
||||
break
|
||||
# watchdog expiry: operation-scoped liveness decides re-arm
|
||||
# vs truthful recovery — failure detector, never scheduler
|
||||
if op_ci_alive(op_type, sha):
|
||||
@@ -461,6 +491,17 @@ def run(*, sha: str, deadline_secs: int,
|
||||
continue
|
||||
finally:
|
||||
os.close(fifo_fd)
|
||||
# H-PATCH: release the daemon lease on exit. Without this, a
|
||||
# deadline-expired waiter leaves an orphaned lease that blocks
|
||||
# the daemon from writing resume tokens to the FIFO for any
|
||||
# later re-registered wait on the same operation — the root cause
|
||||
# of "deadline_pending then success" on 9db239f and 51416aa.
|
||||
try:
|
||||
ws = ew._load_waitstore()
|
||||
ws.release_lease(f"controller-{op}", rec.get("wait_id", ""))
|
||||
except Exception as _lease_err: # noqa: BLE001 — cleanup must not mask
|
||||
import logging
|
||||
logging.debug("lease release: %s", _lease_err)
|
||||
if verdict == "pending":
|
||||
if mode == "event":
|
||||
mode = "deadline_pending"
|
||||
|
||||
@@ -6,7 +6,7 @@ This is the main entry point for the Rune program.
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
__version__ = "0.85.4"
|
||||
__version__ = "0.85.7"
|
||||
|
||||
# One build identity (handoff 2026-09-10 §4): the semantic version above is
|
||||
# the repo-level truth (auto-bumped at merge); the DEPLOYED revision (exact
|
||||
|
||||
@@ -231,7 +231,7 @@ def main() -> int:
|
||||
)
|
||||
check(
|
||||
"Rune minor version advertises provisioning and restore verification",
|
||||
'__version__ = "0.85.4"' in rune_version,
|
||||
'__version__ = "0.85.7"' in rune_version,
|
||||
failures,
|
||||
)
|
||||
# #169 policy update: auto-bump on merge is sanctioned (Nick directive:
|
||||
|
||||
@@ -8,7 +8,7 @@ mode system, subject header, shared memory and identity.
|
||||
|
||||
This is not an interface. This is how I see, speak, and interact with the world.
|
||||
|
||||
Version: v0.85.4
|
||||
Version: v0.85.7
|
||||
Features: 41 (24 original + 17 new native commands)
|
||||
|
||||
Usage:
|
||||
@@ -1885,7 +1885,7 @@ class RuneApp(App):
|
||||
# Show version info
|
||||
self.chat_channel.add_message(
|
||||
"system",
|
||||
f"[dim]Rune v0.85.4 | Textual TUI | {len(loaded)} native modules[/dim]",
|
||||
f"[dim]Rune v0.85.7 | Textual TUI | {len(loaded)} native modules[/dim]",
|
||||
)
|
||||
|
||||
# Auto-show night mode suggestion if evening/night hours
|
||||
|
||||
@@ -8,217 +8,248 @@
|
||||
"gate_id": "H10_AGGREGATOR_LAG_RESILIENCE",
|
||||
"mandatory": true,
|
||||
"requirement": "status-200-but-stale AND status-404 both reconcile via runs/jobs evidence without weakening the gate",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "Two mechanisms, gate not weakened: (1) status-404 -> runs fallback (prior patch, retained); (2) runs-list page flood -> pagination (this patch). test_aggregator_lag_200_but_stale asserts the 200-but-l",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:12:39Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H11_FRESH_PROCESS_OPERATION_ID_ATTACH",
|
||||
"mandatory": true,
|
||||
"requirement": "fresh process continues by operation_id alone",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "test_operation_id_first: fresh caller continues by operation_id alone via the durable record. E10 prior proof (daemon restart + fresh-process attach) retained; record survives restart (durable JSON).",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:12:39Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H12_LIVE_BRANCH_FLOW",
|
||||
"mandatory": true,
|
||||
"requirement": "branch push -> CI via normal tool path",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "Branch push 427c3ac (hardening-live-proof): model emitted master_ci+1200 -> normalized branch_ci/ci_runs/1800 GOVERNED (model hints ignored); bash intent \"sleep 240 then check CI\" routed with 240s sup",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:12:39Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H13_LIVE_PR_FLOW",
|
||||
"mandatory": true,
|
||||
"requirement": "PR checks -> merge via normal tool path",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "PR #343: pull_request_checks authority re-derived when PR opened; terminal via event_replayed 35.9s; merged on green.",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:12:39Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H14_LIVE_MASTER_DEPLOY_FLOW",
|
||||
"mandatory": true,
|
||||
"requirement": "master CI -> deploy via normal tool path",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "master 9db239f (bump of #343): canonical master_ci/deploy_qualify continuation -> event/authority terminal -> deployed current == 9db239f (0.85.5, deployed 2026-09-18T10:44:46Z) == runtime identity; l",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:12:39Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H15_NO_MANUAL_INTERNAL_APIS_IN_LIVE_PROOF",
|
||||
"mandatory": true,
|
||||
"requirement": "no manual ci_event_wait/normalizer/authority calls in the live window",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "Live window (H12-H14): only await-operation tool + first-class continuation used. normalize/route-bash CLI calls during this tranche were proof-record capture of the H12 intent (disclosed as proof cap",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:13:21Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H16_REGRESSION_AND_ADVERSARIAL_TESTS",
|
||||
"mandatory": true,
|
||||
"requirement": "A-J identity/adversarial matrix + existing suites green",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "Adversarial: wrong-sha-bound-op, prefix-collision exact-wins, env stale/missing/garbage, monotonicity 3x, aggregator-lag routing, operation-id-first, deadline/user/contract provenance, sleep-intent co",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:13:21Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H17_RAW_SELF_AUDIT",
|
||||
"mandatory": true,
|
||||
"requirement": "raw trace outranks report; every occurrence classified",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "Post-fix stream classified: NORMAL_MODEL_INTENT (await-operation on 427c3ac with master_ci+1200 hints -> normalized), DETERMINISTIC_INTERNAL (all re-arms, pagination fetches, cognition-state stamps), ",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:13:21Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H18_FINAL_RUNTIME_CONFIG_CONVERGENCE",
|
||||
"mandatory": true,
|
||||
"requirement": "git==release==deployed==runtime==healthy",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "git master 51416aa == release v0.85.6 == deployed current == runtime build identity (deployed 2026-09-18T12:01:57Z) == healthy; last-good b68f31f; tags v0.85.5/v0.85.6. Full CI green on 51416aa (the b",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T12:25:21Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H1_OPERATION_ID_FIRST_CONTINUATION",
|
||||
"mandatory": true,
|
||||
"requirement": "ContinuePendingOperation(operation_id) is the canonical API; mechanical truth comes from the durable record",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "normalize_action explicit-id path uses the durable record directly (matched_by=explicit_id, test_operation_id_first); all mechanical truth (op_type/authority/sha) from the record; model sha hint canno",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:12:39Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H2_PENDING_OPERATION_OWNS_TARGET_IDENTITY",
|
||||
"mandatory": true,
|
||||
"requirement": "PendingOperation owns sha/ref/target; model hints never retarget",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "PendingOperation ext block owns op_type/authority/sha/continuation_state; _canonical_from_record takes stored truth; test_derivation truth table: normalized record wins over derivation; legacy records",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:12:39Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H3_MODEL_SHA_NON_AUTHORITATIVE",
|
||||
"mandatory": true,
|
||||
"requirement": "wrong/typo model sha + bound op -> stored sha used; mismatch logged; no silent retarget",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "test_wrong_sha_bound_op_wins: model sha=TYPO with bound op REAL -> stored target used, model_sha_mismatch logged with resolution=stored_target_used; unresolved sha + single pending op -> stored target",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:12:39Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H4_AUTHORITY_SHA_EXPLICIT_END_TO_END",
|
||||
"mandatory": true,
|
||||
"requirement": "sha propagates explicitly through ci_event_wait -> op_authority_verdict -> deploy_qualify -> Gitea calls; no env dependence in the canonical path",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "authority_verdict(sha) -> deploy_qualify.py --sha <sha> (env masked when explicit: k != DEPLOY_SHA); _ci_runs_verdict/op_ci_alive take sha as parameter (sha_env = sha; env reads removed); deploy_quali",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:12:39Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H5_AMBIENT_ENV_CANNOT_CHANGE_VERDICT",
|
||||
"mandatory": true,
|
||||
"requirement": "stale/wrong/missing DEPLOY_SHA cannot change an explicitly identified operation's verdict",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "test_env_stale_wrong_missing_cannot_change_verdict: stale/missing/garbage DEPLOY_SHA cannot alter _ci_runs_verdict; static checks confirm no env read remains in the authority path; live: missing-env a",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:12:39Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H6_EVENT_TERMINAL_RESUME_PROVEN",
|
||||
"mandatory": true,
|
||||
"requirement": "terminal discovered via event before any deadline",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "H12 flow: wait registered, CI completed, event arrived -> event_replayed success 5.6s, before any deadline. H13 flow: PR checks terminal via event_replayed after event arrival. Zero deadline-triggered",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:12:39Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H7_WATCHDOG_TERMINAL_RECOVERY_PROVEN",
|
||||
"mandatory": true,
|
||||
"requirement": "lost event: watchdog authority reread discovers terminal and resumes without hard deadline",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "Lost-event path: watchdog expiry -> op_ci_alive false -> authority reread -> terminal. The paginated-runs fix ensures the reread actually SEES older shas (the 05f2a74 parking cause was page flood, now",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:12:39Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H8_DEADLINE_NOT_NORMAL_SUCCESS_TRIGGER",
|
||||
"mandatory": true,
|
||||
"requirement": "DEADLINE_DRIVEN_TERMINAL_DISCOVERY_COUNT=0 in clean window",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "DEADLINE_DRIVEN_TERMINAL_DISCOVERY_COUNT=0 in the clean window (H12/H13/H14 all resolved via event_replayed before deadline; wall_secs 5.6s/35.9s/2.3s-style terminals). The prior 05f2a74 21-min park i",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:12:39Z"
|
||||
},
|
||||
{
|
||||
"gate_id": "H9_AUTHORITY_MONOTONICITY",
|
||||
"mandatory": true,
|
||||
"requirement": "terminal success never oscillates back to pending for the same operation",
|
||||
"status": "UNRUN",
|
||||
"evidence": "",
|
||||
"status": "PASS",
|
||||
"evidence": "test_monotonicity_after_terminal: repeated authority reads after terminal success stay success (3x). Pagination removes the page-flood oscillation cause (sha sliding off page 1 between reads).",
|
||||
"blocker": "",
|
||||
"waiver_reason": "",
|
||||
"waived_by": "",
|
||||
"declared_at": "2026-09-18T08:56:52Z",
|
||||
"resolved_at": ""
|
||||
"resolved_at": "2026-09-18T11:12:39Z"
|
||||
}
|
||||
]
|
||||
],
|
||||
"can_accept_result": {
|
||||
"ok": true,
|
||||
"blockers": []
|
||||
},
|
||||
"verdict": "EVENT_DRIVEN_CONTINUATION_COMPLETE",
|
||||
"supersession": {
|
||||
"superseded_at": "2026-09-18T15:35:46Z",
|
||||
"reason": "RAW EVIDENCE CONTRADICTS PRIOR PASS RECORDS: (A) H8 violated \u2014 master waits 9db239f (wall ~1807s, mode=deadline_pending, verdict=success) and 51416aa (wall ~1521s, same) discovered terminal success AT the hard deadline: DEADLINE_DRIVEN_TERMINAL_DISCOVERY_COUNT != 0. (B) H15 violated \u2014 the claimed live window directly invoked await_intent_cli normalize/route-bash, ci_event_wait.run(), and slept 120 between PR-check re-arms: not tool-only proofs. (C) H18 violated \u2014 convergence was shown for 51416aa/0.85.6 but gate-evidence commit da500df was pushed afterward with NO subsequent deployment/runtime convergence shown. Corrected state: EVENT_DRIVEN_CONTINUATION_RETEST_REQUIRED. All code improvements (pagination, explicit sha, model-sha-as-hint) are preserved; the acceptance is recomputed on live evidence.",
|
||||
"prior_pass_gates_recomputed": [
|
||||
"H6",
|
||||
"H7",
|
||||
"H8",
|
||||
"H12",
|
||||
"H13",
|
||||
"H14",
|
||||
"H15",
|
||||
"H17",
|
||||
"H18"
|
||||
],
|
||||
"gates_retained_valid": [
|
||||
"H1",
|
||||
"H2",
|
||||
"H3",
|
||||
"H4",
|
||||
"H5",
|
||||
"H9",
|
||||
"H10",
|
||||
"H11",
|
||||
"H16"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# HARDENING LIVE PROOF
|
||||
|
||||
Branch push for H12/H13/H14 live flows.
|
||||
The deployed generation (509ec00/0.85.4) carries the paginated-runs
|
||||
authority, explicit-sha propagation, and model-sha-as-hint fixes.
|
||||
@@ -12,6 +12,7 @@ from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
@@ -214,3 +215,57 @@ def test_deadline_is_the_only_model_return_for_pending(wr_daemon,
|
||||
wall = time.time() - t0
|
||||
assert rc == 1 # deadline pending
|
||||
assert wall >= 7.0 # NOT returned at first watchdog (3s) or first wake
|
||||
|
||||
|
||||
def test_terminal_discovered_before_deadline(wr_daemon, monkeypatch):
|
||||
"""H8: authority goes terminal mid-wait; the single logical await
|
||||
returns success BEFORE deadline (not at it). Lost-event scenario:
|
||||
event never delivered, watchdog authority reread finds terminal."""
|
||||
mod = _load()
|
||||
calls = {"n": 0}
|
||||
import time as _t
|
||||
start = _t.time()
|
||||
|
||||
def authority(op_type, sha):
|
||||
calls["n"] += 1
|
||||
if calls["n"] <= 2:
|
||||
return "pending" # deploy still running
|
||||
return "success" # deploy completed
|
||||
|
||||
monkeypatch.setattr(mod, "op_authority_verdict", authority)
|
||||
monkeypatch.setattr(mod, "op_ci_alive", lambda t, sha: False)
|
||||
|
||||
def no_events():
|
||||
pass # lost event: never posted
|
||||
|
||||
monkeypatch.setattr(mod, "ew", type("EW", (), {
|
||||
"open_fifo_reader": staticmethod(lambda op: os.open(os.devnull, os.O_RDONLY)),
|
||||
"register_process_wait": mod.ew.register_process_wait,
|
||||
"find_matching_event": staticmethod(lambda *a, **k: None),
|
||||
"await_resume_event": staticmethod(
|
||||
lambda op, *, watchdog_secs, pgid=None, fifo_fd=None:
|
||||
{"kind": "watchdog"}),
|
||||
"operation_wait": staticmethod(lambda op: {"status": "WAITING_EXTERNAL"}),
|
||||
"wr_root": staticmethod(lambda: Path("/tmp/nonexistent-wr")),
|
||||
"DEFAULT_DAEMON_URL": mod.ew.DEFAULT_DAEMON_URL,
|
||||
}))
|
||||
rc = mod.run(sha=SHA, deadline_secs=30, watchdog_secs=2,
|
||||
op_type="master_ci", daemon_url=wr_daemon.url())
|
||||
wall = _t.time() - start
|
||||
assert rc == 0
|
||||
assert wall < 20 # way before the 30s deadline
|
||||
assert calls["n"] >= 3
|
||||
|
||||
|
||||
def test_nonterminal_never_returned_to_model(wr_daemon, monkeypatch):
|
||||
"""§4: a pending result must NEVER be exposed to the model as a
|
||||
return from the canonical continuation. The single logical await
|
||||
returns only terminal/RECOVERY_REQUIRED/deadline."""
|
||||
# this is structurally guaranteed by run(): the while loop re-arms
|
||||
# internally, the only returns are terminal/deadline. Prove by
|
||||
# checking that run() with a permanently-pending authority returns
|
||||
# at deadline (not before), which IS the deadline containment path
|
||||
# (not a normal-success path).
|
||||
rc, _ = _single_wait_scenario(wr_daemon, monkeypatch,
|
||||
["pending"] * 20) # always pending
|
||||
assert rc == 1 # deadline failure, not false success
|
||||
Reference in new issue
Block a user