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
105 changes: 105 additions & 0 deletions docs/evals/v4.0.8-agent-policy-pack-degraded-truth.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
{
"schema_id": "contextlattice_eval_ledger.v1",
"feature": "agent_policy_pack_degraded_truth",
"lane": "shared_public_safe",
"release_train": "v4.0.8",
"recorded_at": "2026-08-04T08:10:55Z",
"baseline": {
"case_count": 1,
"transport_failure": "mock curl exit 7 with no response body",
"helper_exit_code": 0,
"pack_parseable": true,
"reported_ok": true,
"reported_retrieval_degraded": false,
"false_healthy_rate": 1.0
},
"target": {
"pack_remains_available_during_retrieval_failure": true,
"transport_failure_reports_ok": false,
"transport_failure_reports_retrieval_degraded": true,
"degraded_memory_warning_required": true,
"false_healthy_rate": 0.0
},
"holdout": {
"kind": "isolated_response_contract_matrix",
"network_dependency": false,
"mock_curl_exit_code": 7,
"mock_curl_stdout_bytes": 0,
"case_count": 15,
"cases": [
"transport failure",
"empty response",
"invalid JSON",
"non-object JSON",
"empty object",
"explicit error response with upstream warning",
"native degraded response with upstream warning",
"inconsistent degraded lifecycle state",
"malformed degraded flag",
"malformed ok flag",
"malformed result_state",
"malformed warnings",
"malformed result row",
"response larger than host ARG_MAX",
"healthy ready response"
],
"assertions": [
"helper exits zero with a parseable static policy pack",
"top-level ok is false",
"retrieval degraded is true",
"warning explicitly selects degraded-memory mode"
]
},
"results": {
"status": "pass",
"baseline_regression_test": "failed_for_expected_false_healthy_assertion",
"fixed_regression_test": "passed_7_tests_15_cases",
"shellcheck": "passed",
"python_compile": "passed",
"live_success_path": "passed_ok_true_degraded_false_8_results",
"agent_context_audit": "change_relevant_checks_passed_overall_exit_1_from_preexisting_context_size_budget",
"installed_payload_identity": "passed_sha256_34e79a11a712b0a07823fdd2c0b7bc53f0448db668255647e84d9b485eec0156",
"installed_failure_path": "passed_ok_false_degraded_true",
"installed_success_path": "passed_ok_true_degraded_false_8_results",
"structured_review": "three_distinct_p1_findings_applied_and_independently_validated_plus_one_preexisting_p2_closed"
},
"cost": {
"llm_calls": 0,
"provider_tokens": 0,
"new_services": 0,
"new_routes": 0,
"new_dependencies": 0,
"additional_network_calls": 0
},
"latency": {
"baseline_regression_secs": 0.119,
"fixed_regression_secs": 1.302
},
"tool_calls": {
"mock_curl_calls_per_case": 1,
"mock_curl_calls_full_suite": 15,
"runtime_process_restarts": 0,
"runtime_container_restarts": 0
},
"failures": [
{
"stage": "baseline",
"failure": "curl_json failure was discarded with an unconditional true fallback, and an empty response was interpreted as a healthy empty search",
"resolution": "carry transport success into typed response normalization; recognize degraded lifecycle state; reject malformed result rows; and require a canonical degraded-memory directive on every degraded response"
},
{
"stage": "structured_review",
"failure": "the response body was passed to Python through argv, so a body above the host argument limit could prevent static-pack emission",
"resolution": "stream the body on file descriptor 3 and cover a generated response larger than SC_ARG_MAX"
}
],
"reproduction": [
"python3 -m unittest scripts.tests.test_agent_policy_pack",
"shellcheck -x -P scripts/agent_hooks scripts/agent_hooks/agent_policy_pack.sh",
"python3 -m json.tool docs/evals/v4.0.8-agent-policy-pack-degraded-truth.json"
],
"rollback": {
"source": "revert the agent_policy_pack degraded-truth commit",
"installed_payload": "rerun the prior version's global agent-tools installer; no service restart is required"
}
}
71 changes: 59 additions & 12 deletions scripts/agent_hooks/agent_policy_pack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,66 @@ print(json.dumps({
}))
PY
)"
search_out="$(curl_json POST "${BASE}/memory/search" "$payload" "$TIMEOUT" || true)"
python3 - "$AGENT" "$PROJECT" "$TOPIC" "$MODE" "$BASE" "$search_out" <<'PY'
import json, sys
agent, project, topic, mode, base, raw = sys.argv[1:]
try:
search = json.loads(raw) if raw else {}
except Exception as exc:
search = {'degraded': True, 'error': str(exc)}
results = search.get('results') if isinstance(search, dict) else []
search_transport_ok=true
if ! search_out="$(curl_json POST "${BASE}/memory/search" "$payload" "$TIMEOUT")"; then
search_transport_ok=false
fi
python3 - "$AGENT" "$PROJECT" "$TOPIC" "$MODE" "$BASE" "$search_transport_ok" 3<<<"$search_out" <<'PY'
import json, os, sys
agent, project, topic, mode, base, transport_ok_raw = sys.argv[1:]
raw = os.fdopen(3).read()
transport_ok = transport_ok_raw == 'true'

def degraded_search(message):
return {
'degraded': True,
'warnings': [f'{message}; continue in degraded-memory mode.'],
}

def invalid_response_shape(search):
typed_fields = (
('ok', bool),
('degraded', bool),
('result_state', str),
)
for key, expected_type in typed_fields:
if key in search and not isinstance(search[key], expected_type):
return True
if 'warnings' in search:
warnings = search['warnings']
if not isinstance(warnings, list) or any(not isinstance(item, str) for item in warnings):
return True
results = search.get('results')
if isinstance(results, list) and any(not isinstance(item, dict) for item in results):
return True
return False

if not transport_ok:
search = degraded_search('ContextLattice retrieval request failed')
elif not raw.strip():
search = degraded_search('ContextLattice retrieval returned an empty response')
else:
try:
search = json.loads(raw)
except Exception:
search = degraded_search('ContextLattice retrieval returned invalid JSON')
if not isinstance(search, dict):
search = degraded_search('ContextLattice retrieval returned an invalid response shape')
elif invalid_response_shape(search):
search = degraded_search('ContextLattice retrieval returned an invalid response shape')
result_state = search.get('result_state', '').strip().lower()
degraded = search.get('degraded') is True or search.get('ok') is False or result_state == 'degraded'
results = search.get('results')
if not isinstance(results, list):
if not degraded:
search = degraded_search('ContextLattice retrieval returned an invalid response shape')
degraded = True
results = []
warnings = list(search.get('warnings') or [])
if degraded and not any('degraded-memory mode' in warning for warning in warnings):
warnings.append('ContextLattice retrieval is degraded; continue in degraded-memory mode.')
pack = {
'ok': not bool(search.get('degraded')),
'ok': not degraded,
'agent_id': agent,
'project': project,
'topic_path': topic,
Expand All @@ -81,8 +128,8 @@ pack = {
'checkpoint': 'contextlattice_checkpoint --project <project> --topic-path <topic_path> --file notes/<agent>/checkpoint.md --stdin',
},
'retrieval': {
'degraded': bool(search.get('degraded')),
'warnings': search.get('warnings') or [],
'degraded': degraded,
'warnings': warnings,
'result_count': len(results),
'top_results': [
{k: item.get(k) for k in ('file','topic_path','source','score','summary') if isinstance(item, dict) and k in item}
Expand Down
129 changes: 129 additions & 0 deletions scripts/tests/test_agent_policy_pack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#!/usr/bin/env python3

import json
import os
from pathlib import Path
import subprocess
import tempfile
import unittest


SCRIPT = Path(__file__).parents[1] / "agent_hooks" / "agent_policy_pack.sh"


class AgentPolicyPackTest(unittest.TestCase):
def run_with_fake_curl(
self,
*,
stdout: str = "",
stdout_size: int = 0,
exit_code: int = 0,
) -> subprocess.CompletedProcess[str]:
with tempfile.TemporaryDirectory() as temp_dir:
fake_bin = Path(temp_dir)
fake_curl = fake_bin / "curl"
fake_curl.write_text(
"#!/bin/zsh\n"
"if [[ -n \"${FAKE_CURL_STDOUT_FILE:-}\" ]]; then\n"
" /bin/cat \"$FAKE_CURL_STDOUT_FILE\"\n"
"else\n"
" print -rn -- \"${FAKE_CURL_STDOUT:-}\"\n"
"fi\n"
"exit \"${FAKE_CURL_EXIT:-0}\"\n",
encoding="utf-8",
)
fake_curl.chmod(0o755)

env = os.environ.copy()
env["PATH"] = f"{fake_bin}:{env['PATH']}"
env["FAKE_CURL_STDOUT"] = stdout
env["FAKE_CURL_EXIT"] = str(exit_code)
if stdout_size:
response_file = fake_bin / "response.txt"
response_file.write_text("x" * stdout_size, encoding="utf-8")
env["FAKE_CURL_STDOUT_FILE"] = str(response_file)
return subprocess.run(
[str(SCRIPT), "--timeout", "1"],
check=False,
capture_output=True,
text=True,
env=env,
)

def assert_degraded(self, result: subprocess.CompletedProcess[str], warning: str) -> None:
self.assertEqual(result.returncode, 0, result.stderr)
payload = json.loads(result.stdout)
self.assertIs(payload["ok"], False)
self.assertIs(payload["retrieval"]["degraded"], True)
warnings = " ".join(payload["retrieval"]["warnings"])
self.assertIn(warning, warnings)
self.assertIn("degraded-memory mode", warnings)
for key in ("mission", "objective", "goal", "usage"):
self.assertIn(key, payload)
self.assertIn("search", payload["usage"])

def test_transport_failure_is_reported_as_degraded(self) -> None:
self.assert_degraded(
self.run_with_fake_curl(exit_code=7),
"request failed",
)

def test_unusable_responses_are_reported_as_degraded(self) -> None:
cases = (
("", "empty response"),
("not-json", "invalid JSON"),
("[]", "invalid response shape"),
("{}", "invalid response shape"),
)
for stdout, warning in cases:
with self.subTest(stdout=stdout):
self.assert_degraded(self.run_with_fake_curl(stdout=stdout), warning)

def test_explicit_error_response_is_reported_as_degraded(self) -> None:
result = self.run_with_fake_curl(stdout='{"ok":false,"warnings":["upstream unavailable"]}')

self.assert_degraded(result, "upstream unavailable")

def test_native_degraded_states_include_mode_directive(self) -> None:
cases = (
'{"degraded":true,"result_state":"degraded","results":[],"warnings":["source timeout"]}',
'{"degraded":false,"result_state":"degraded","results":[],"warnings":[]}',
)
for stdout in cases:
with self.subTest(stdout=stdout):
self.assert_degraded(self.run_with_fake_curl(stdout=stdout), "degraded-memory mode")

def test_malformed_contract_fields_are_reported_as_degraded(self) -> None:
cases = (
'{"degraded":0,"results":[]}',
'{"ok":"false","results":[]}',
'{"degraded":false,"result_state":0,"results":[]}',
'{"degraded":true,"results":[],"warnings":"source timeout"}',
'{"degraded":false,"results":[1]}',
)
for stdout in cases:
with self.subTest(stdout=stdout):
self.assert_degraded(self.run_with_fake_curl(stdout=stdout), "invalid response shape")

def test_response_larger_than_arg_max_retains_static_pack(self) -> None:
response_size = os.sysconf("SC_ARG_MAX") + 1024

self.assert_degraded(
self.run_with_fake_curl(stdout_size=response_size),
"invalid JSON",
)

def test_healthy_response_remains_healthy(self) -> None:
result = self.run_with_fake_curl(
stdout='{"degraded":false,"result_state":"ready","results":[{"file":"proof.md"}],"warnings":[]}'
)

self.assertEqual(result.returncode, 0, result.stderr)
payload = json.loads(result.stdout)
self.assertIs(payload["ok"], True)
self.assertIs(payload["retrieval"]["degraded"], False)
self.assertEqual(payload["retrieval"]["result_count"], 1)


if __name__ == "__main__":
unittest.main()