Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ The same explicitly authorized rollover contract applies to the later supported
| `acceptance-revalidation-v14` | Settled V13 on the integrated U03 candidate |
| `acceptance-revalidation-v15` | Settled V14, including its invalid-JSON failure |
| `acceptance-revalidation-v16` | Settled V15, including the stale-confirmation U03 failure |
| `acceptance-revalidation-v17` | Settled V16, including the cancellation-state U03 failure |

Before preparation, retain the predecessor ledger, binding and guard at their pinned
fingerprints and preserve the entire earlier history chain. The selected policy's
Expand Down Expand Up @@ -542,6 +543,12 @@ costs; the earlier U02 gate remains evidence for its original candidate only. Th
same cumulative USD200 ceiling, three unknown liabilities and purpose/token caps
apply. Fresh acceptance must bind the changed service rather than relabel old proof.

V17 retains the permanently halted V16 ledger, binding and guard for cancellation
diagnostic revalidation. Preserve the original U02 gate and incomplete U03 result;
numeric HTTP/Result failure diagnostics do not establish a root cause or a pass.
The same cumulative USD200 ceiling, three unknown liabilities and purpose/token
caps apply. Establish fresh acceptance for the changed candidate.

Issue the evidence-bound U02 gate only after those inputs validate. Gate artifact references are
relative to the private directory containing the gate; place the referenced artifacts there:

Expand Down
4 changes: 2 additions & 2 deletions services/agent/data/repository_corpus_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
},
{
"doc_id": "repository-development",
"version": "sha256-df792c4eeb93390edb6fccb5896153f620d8dfd9b7dd1735080baeaf7edc5a32",
"chunk_id": "repository-development:sha256-df792c4eeb93390edb6fccb5896153f620d8dfd9b7dd1735080baeaf7edc5a32:1",
"version": "sha256-f34f2a60cef2672d30a8208f0e2ebcc3a897eccd936808f69c7aff6375802379",
"chunk_id": "repository-development:sha256-f34f2a60cef2672d30a8208f0e2ebcc3a897eccd936808f69c7aff6375802379:1",
"source_path": "docs/DEVELOPMENT.md",
"access_scope": "repository-public",
"sample_kind": "real",
Expand Down
2 changes: 1 addition & 1 deletion services/agent/e2e_u03_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -1270,7 +1270,7 @@ async def _cancel_old_run_fence(
current_code, current = _envelope(current_response)
if current_response.status_code != 200 or current_code != 0:
analysis_task.cancel()
raise ValueError("cancel_fence_state_unavailable")
raise ValueError(f"cancel_fence_state_unavailable:http={current_response.status_code}:code={current_code}")
if current.get("status") == "analyzing":
analysis_run_id = current.get("runId")
if not analysis_run_id:
Expand Down
14 changes: 14 additions & 0 deletions services/agent/src/authorized_budget_period.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
REVALIDATION_V14_POLICY_ID = "acceptance-revalidation-v14"
REVALIDATION_V15_POLICY_ID = "acceptance-revalidation-v15"
REVALIDATION_V16_POLICY_ID = "acceptance-revalidation-v16"
REVALIDATION_V17_POLICY_ID = "acceptance-revalidation-v17"
REVALIDATION_POLICY_IDS = frozenset({REVALIDATION_POLICY_ID, REVALIDATION_V2_POLICY_ID, REVALIDATION_V3_POLICY_ID, REVALIDATION_V4_POLICY_ID, REVALIDATION_V5_POLICY_ID, REVALIDATION_V6_POLICY_ID, REVALIDATION_V7_POLICY_ID, REVALIDATION_V8_POLICY_ID, REVALIDATION_V9_POLICY_ID, REVALIDATION_V10_POLICY_ID, REVALIDATION_V11_POLICY_ID, REVALIDATION_V12_POLICY_ID})
REVALIDATION_V2_HISTORY = MappingProxyType({
"attempts": 164, "known_actual_micro_usd": 42_307,
Expand Down Expand Up @@ -251,6 +252,17 @@
})
REVALIDATION_POLICY_IDS = REVALIDATION_POLICY_IDS | {REVALIDATION_V16_POLICY_ID}

REVALIDATION_V17_HISTORY = MappingProxyType({
"attempts": 1390, "known_actual_micro_usd": 401_694,
"known_committed_micro_usd": 12_296_114,
"unknown_attempts": 3, "unknown_encumbrance_micro_usd": 2_359_296,
"cumulative_attempt_limit": 1631, "cumulative_limit_micro_usd": 200_000_000,
})
REVALIDATION_V17_POLICY = MappingProxyType({
**REVALIDATION_V16_POLICY, "history": REVALIDATION_V17_HISTORY,
})
REVALIDATION_POLICY_IDS = REVALIDATION_POLICY_IDS | {REVALIDATION_V17_POLICY_ID}


def policy_for(policy_id: str):
if policy_id == POLICY_ID:
Expand Down Expand Up @@ -287,6 +299,8 @@ def policy_for(policy_id: str):
return REVALIDATION_V15_POLICY
if policy_id == REVALIDATION_V16_POLICY_ID:
return REVALIDATION_V16_POLICY
if policy_id == REVALIDATION_V17_POLICY_ID:
return REVALIDATION_V17_POLICY
raise PeriodError("unsupported policy")


Expand Down
27 changes: 23 additions & 4 deletions services/agent/src/revalidation_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,13 +294,30 @@ def _check_unknown_rollover(snapshot, guard, *, predecessor="v2"):
}


V16_ROLLOVER_IDENTITY = {
"period_id": "revalidation-v16-20261011",
"identity": "c1956ef57b684979a5550b173a7ecde4",
"config_sha256": "43a23d85bd6afd63246b277cc3076bfcc8fd51ce5d41e64fcc70aba71b8742bc",
"policy_id": "acceptance-revalidation-v16",
}
V16_ROLLOVER_SHA256 = {
"budget.sqlite3": "22f4236db84a84708c2519c672573ad970941e9934213b5462b2cb58ea9e51b9",
"binding.json": "1212a6787c87526ebd067404336e49e99dc6d72c563e5244658a20a393831d81",
"dav58-increment-c1956ef57b684979a5550b173a7ecde4.json": "530b8f4d354f22ebc3a17155ea3b9ccd6c9061c944a664e3b427559f8f431956",
}


def _validate_rollover_history(sources, *, settled_policy="v1"):
from authorized_budget_period import REVALIDATION_V14_HISTORY, REVALIDATION_V15_HISTORY, REVALIDATION_V16_HISTORY
from authorized_budget_period import REVALIDATION_V14_HISTORY, REVALIDATION_V15_HISTORY, REVALIDATION_V16_HISTORY, REVALIDATION_V17_HISTORY
from authorized_budget_period import PeriodError, PeriodIdentity, REVALIDATION_V2_HISTORY, REVALIDATION_V4_HISTORY, REVALIDATION_V5_HISTORY, REVALIDATION_V6_HISTORY, REVALIDATION_V7_HISTORY, REVALIDATION_V8_HISTORY, REVALIDATION_V9_HISTORY, REVALIDATION_V10_HISTORY, REVALIDATION_V11_HISTORY, REVALIDATION_V12_HISTORY, _parent, _file
from model_budget import ModelBudget, authorization_slot
from dav58_live_guard import IncrementalGuard

if settled_policy == "v15":
if settled_policy == "v16":
original = _validate_rollover_history(sources, settled_policy="v15")
identity, fingerprints = V16_ROLLOVER_IDENTITY, V16_ROLLOVER_SHA256
totals, history = (104, 35_977, 932_400), REVALIDATION_V17_HISTORY
elif settled_policy == "v15":
original = _validate_rollover_history(sources, settled_policy="v14")
identity, fingerprints = V15_ROLLOVER_IDENTITY, V15_ROLLOVER_SHA256
totals, history = (103, 35_648, 922_800), REVALIDATION_V16_HISTORY
Expand Down Expand Up @@ -384,7 +401,7 @@ def _validate_rollover_history(sources, *, settled_policy="v1"):
try:
# Validate sealed receipts without making the permanently halted journal resumable.
receipt_view = guard
if settled_policy in {"v13", "v14", "v15"}:
if settled_policy in {"v13", "v14", "v15", "v16"}:
if guard.get("halted") is not True:
raise PeriodError("previous guard must be permanently halted")
receipt_view = {**guard, "halted": False}
Expand All @@ -397,10 +414,12 @@ def _validate_rollover_history(sources, *, settled_policy="v1"):


def validate_history(sources, *, policy_id="acceptance-revalidation-v1"):
from authorized_budget_period import REVALIDATION_V13_POLICY_ID, REVALIDATION_V14_POLICY_ID, REVALIDATION_V15_POLICY_ID, REVALIDATION_V16_POLICY_ID
from authorized_budget_period import REVALIDATION_V13_POLICY_ID, REVALIDATION_V14_POLICY_ID, REVALIDATION_V15_POLICY_ID, REVALIDATION_V16_POLICY_ID, REVALIDATION_V17_POLICY_ID
from authorized_budget_period import PeriodError, REVALIDATION_HISTORY, _parent, _file
from authorized_budget_period import REVALIDATION_POLICY_ID, REVALIDATION_V2_POLICY_ID, REVALIDATION_V3_POLICY_ID, REVALIDATION_V4_POLICY_ID, REVALIDATION_V5_POLICY_ID, REVALIDATION_V6_POLICY_ID, REVALIDATION_V7_POLICY_ID, REVALIDATION_V8_POLICY_ID, REVALIDATION_V9_POLICY_ID, REVALIDATION_V10_POLICY_ID, REVALIDATION_V11_POLICY_ID, REVALIDATION_V12_POLICY_ID

if policy_id == REVALIDATION_V17_POLICY_ID:
return _validate_rollover_history(sources, settled_policy="v16")
if policy_id == REVALIDATION_V16_POLICY_ID:
return _validate_rollover_history(sources, settled_policy="v15")
if policy_id == REVALIDATION_V14_POLICY_ID:
Expand Down
23 changes: 23 additions & 0 deletions services/agent/tests/test_delivery_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,29 @@
u03 = importlib.util.module_from_spec(_SPEC)
_SPEC.loader.exec_module(u03)

@pytest.mark.parametrize("status,code", [(502, 50000), (200, 40900)])
def test_cancel_fence_preserves_safe_failed_read_diagnostics(status, code):
import asyncio
import httpx

async def scenario():
async def respond(request):
if request.method == "POST":
data = {"threadId": str(uuid.uuid4()), "draft": {}}
return httpx.Response(200, json={"code": 0, "message": "success", "data": data,
"traceId": "private-trace"})
return httpx.Response(status, json={"code": code, "message": "private-message",
"data": {"reason": "private-reason"},
"traceId": "private-trace"})

async with httpx.AsyncClient(transport=httpx.MockTransport(respond),
base_url="http://localhost") as session:
with pytest.raises(ValueError) as failure:
await u03._cancel_old_run_fence(session, str(uuid.uuid4()))
assert str(failure.value) == f"cancel_fence_state_unavailable:http={status}:code={code}"

asyncio.run(scenario())

def _prior_five_fixture(tmp_path, monkeypatch, *, unsupported_rejected=True, raw_records=None):
import agent_service.gate as gate

Expand Down
17 changes: 17 additions & 0 deletions services/agent/tests/test_v16_confirmation_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,20 @@ def test_confirmation_revalidation_retains_settled_v15_and_unknown_liabilities()
assert policy["limit_micro_usd"] == old["limit_micro_usd"]
assert (history["known_committed_micro_usd"] + history["unknown_encumbrance_micro_usd"]
+ policy["limit_micro_usd"] <= history["cumulative_limit_micro_usd"])


def test_cancellation_revalidation_retains_settled_v16_and_unknown_liabilities():
old = policy_for("acceptance-revalidation-v16")
policy = policy_for("acceptance-revalidation-v17")
history = policy["history"]
assert history["attempts"] == old["history"]["attempts"] + 104 == 1390
assert history["known_actual_micro_usd"] == old["history"]["known_actual_micro_usd"] + 35977 == 401694
assert history["known_committed_micro_usd"] == old["history"]["known_committed_micro_usd"] + 932400 == 12296114
assert history["unknown_attempts"] == old["history"]["unknown_attempts"] == 3
assert history["unknown_encumbrance_micro_usd"] == old["history"]["unknown_encumbrance_micro_usd"] == 2359296
assert history["cumulative_limit_micro_usd"] == old["history"]["cumulative_limit_micro_usd"] == 200000000
assert history["cumulative_attempt_limit"] == history["attempts"] + policy["attempts"] == 1631
assert policy["lanes"] == old["lanes"]
assert policy["limit_micro_usd"] == old["limit_micro_usd"]
assert (history["known_committed_micro_usd"] + history["unknown_encumbrance_micro_usd"]
+ policy["limit_micro_usd"] <= history["cumulative_limit_micro_usd"])
Loading