Reproduced false healthy-state reporting
Pinned sourceb6960706a6ea1797a63e901c34f06cabd0f7e7a5:
|
def _normalize_api_rows(data: Any) -> List[Dict[str, Any]]: |
|
if isinstance(data, list): |
|
return [d for d in data if isinstance(d, dict)] |
|
if isinstance(data, dict): |
|
for key in ("items", "data", "results", "agents", "contracts", "reputation"): |
|
v = data.get(key) |
|
if isinstance(v, list): |
|
return [d for d in v if isinstance(d, dict)] |
|
return [] |
|
|
|
|
|
def fetch_beacon_snapshot( |
|
api_base_url: str = DEFAULT_API_BASE_URL, |
|
*, |
|
timeout_s: float = 8.0, |
|
session: Optional[requests.Session] = None, |
|
) -> Dict[str, Any]: |
|
http = session or requests.Session() |
|
base = (api_base_url or DEFAULT_API_BASE_URL).rstrip("/") |
|
endpoints = { |
|
"agents": f"{base}/api/agents", |
|
"contracts": f"{base}/api/contracts", |
|
"reputation": f"{base}/api/reputation", |
|
} |
|
out: Dict[str, Any] = {"ok": True, "errors": [], "fetched_at": int(time.time())} |
|
for name, url in endpoints.items(): |
|
try: |
|
resp = http.request("GET", url, timeout=timeout_s) |
|
if int(resp.status_code) >= 400: |
|
out["ok"] = False |
|
out["errors"].append(f"{name}: HTTP {resp.status_code}") |
|
out[name] = [] |
|
continue |
|
try: |
|
payload = resp.json() |
|
except Exception: |
|
payload = {} |
|
out[name] = _normalize_api_rows(payload) |
|
except Exception as e: |
|
out["ok"] = False |
|
out["errors"].append(f"{name}: {e}") |
|
out[name] = [] |
and sidebar#L463-L488.
Original fetch/API-poll/sidebar methods with three local HTTP200 responses whose json() raisesValueError produce ok=True, errors=[], counts0/0/0 and sidebarstatusOK. Valid-empty arrays produce the same output. One malformed contracts endpoint plus healthy nonempty agents/reputation retains counts1/0/1 but stillreportsOK/noerror.
Expected: malformed endpoint data is degraded/error state, not a healthy empty network, while valid endpoint data survives. Actual: decode failures are replaced with{} before outer failure handling, leaving okTrue/noerrors. Suggested fix: propagate endpoint-specific decode failures into the established partial-failure/error reporting path without discarding valid endpoints.
Distinct from inclusive inbox polling and already-fixed API baseURL. Symbol/invalidJSON searches matched only unrelated storageJSONLPR829/UDPexamplePR13; no corresponding dashboard decode fix identified.
Reproduction and controls
Python3 stdlib on macOS arm64. Save pinned dashboard.py, inbox.py and this script as repro.py together in an isolated directory, run python3 repro.py. Original reader/poll/display/API/sidebar function ASTs execute unchanged; widgets and HTTP are local fakes. Inbox is a temporary JSONL fixture; known-key/state seams return empty values or no-op. No Textual app, UDP, quick-send, identities/keys, ~/.beacon, live API, account or production writes.
import ast
import json
import time
from pathlib import Path
from collections import Counter
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional
from types import SimpleNamespace
ROOT = Path(__file__).parent
ns = dict(globals(), requests=SimpleNamespace(Session=lambda: None), sound=False, api_base_url='https://fixture.invalid/beacon', DEFAULT_API_BASE_URL='https://fixture.invalid/beacon')
def load_functions(filename, names):
tree = ast.parse((ROOT / filename).read_text())
funcs = [node for node in ast.walk(tree) if isinstance(node, ast.FunctionDef) and node.name in names]
assert len(funcs) == len(names), (filename, names)
exec(compile(ast.fix_missing_locations(ast.Module(body=funcs, type_ignores=[])), filename, 'exec'), ns)
# Only original function ASTs execute: no module imports, app construction, identity, network or send path.
load_functions('inbox.py', {'read_inbox'})
fixture = ROOT / 'fixture.jsonl'
ns.update(_inbox_path=lambda: fixture, load_known_keys=lambda: {}, _read_nonces=lambda: set(), save_known_keys=lambda keys: None, decode_envelopes=lambda text: [])
load_functions('dashboard.py', {'_format_ts', '_short_agent', '_as_text', '_rtc_tip', '_transport_tag', '_entry_to_row', '_row_matches_query', '_normalize_api_rows', 'fetch_beacon_snapshot', '_route_table_id', '_add_row', '_display_row', '_poll_inbox', '_poll_api', '_refresh_sidebar'})
class Widget:
def __init__(self): self.rows = {}; self.text = ''
@property
def row_count(self): return len(self.rows)
def add_row(self, *row): self.rows[len(self.rows)] = row
def update(self, text): self.text = text
class Dashboard:
def __init__(self):
self._last_ts = 0; self._count_today = 0
self._transport_counter = Counter(); self._agent_counter = Counter()
self._history_rows = []; self._visible_rows = []; self._filter_query = ''
self._api_state = {}; self.widgets = {}; self.notifications = []
def query_one(self, name, kind): return self.widgets.setdefault(name, Widget())
def notify(self, *args, **kwargs): self.notifications.append((args, kwargs))
for name in ('_route_table_id', '_add_row', '_display_row', '_poll_inbox', '_poll_api', '_refresh_sidebar'):
setattr(Dashboard, name, ns[name])
ns.update(DataTable=Widget, Static=Widget)
def write_entries(entries): fixture.write_text(''.join(json.dumps(e) + '\n' for e in entries))
a = {'received_at': 1000, 'platform': 'udp', 'from': 'fixture-a', 'text': 'first'}
b = {'received_at': 1000, 'platform': 'udp', 'from': 'fixture-b', 'text': 'second'}
write_entries([a]); d = Dashboard(); d._poll_inbox(); d._poll_inbox()
print('UNCHANGED: expected pings/history/visible/table=1/1/1/1; actual=' + '/'.join(map(str, [d._count_today, len(d._history_rows), len(d._visible_rows), d.widgets['#tbl-all'].row_count])))
print('UNCHANGED counters:', dict(d._transport_counter), dict(d._agent_counter))
assert d._count_today == 2 and len(d._history_rows) == 2
write_entries([a]); d = Dashboard(); d._poll_inbox(); write_entries([a, b]); d._poll_inbox()
print('EQUAL_TIMESTAMP_APPEND: expected distinct pings=2; actual pings=%s messages=%s' % (d._count_today, [r['message'] for r in d._history_rows]))
print('INCLUSIVE_READER: since=1000 returns', [e['text'] for e in ns['read_inbox'](since=1000)])
assert [r['message'] for r in d._history_rows] == ['first', 'first', 'second']
class Response:
status_code = 200
def __init__(self, payload): self.payload = payload
def json(self):
if self.payload == 'BAD': raise ValueError('invalid JSON fixture')
return self.payload
class Session:
def __init__(self, payloads): self.payloads = iter(payloads); self.calls = []
def request(self, method, url, timeout):
self.calls.append((method, url, timeout)); return Response(next(self.payloads))
for label, payloads in [('ALL_INVALID', ['BAD'] * 3), ('VALID_EMPTY', [[], [], []]), ('ONE_INVALID', [[{'id': 'fixture-agent'}], 'BAD', [{'id': 'fixture-reputation'}]])]:
d = Dashboard(); d._http = Session(payloads); d._poll_api(); d._refresh_sidebar()
state = d._api_state
print(label + ': ok=%s errors=%s counts=%s' % (state['ok'], state['errors'], [state[k + '_count'] for k in ('agents', 'contracts', 'reputation')]))
print(label + ' sidebar:', ' | '.join(line for line in d.widgets['#sidebar'].text.splitlines() if line.startswith(('- status:', '- agents:', '- contracts:', '- reputation:', '- last_error:'))))
assert len(d._http.calls) == 3
assert state['ok'] is True and state['errors'] == []
if label == 'ONE_INVALID': assert state['agents_count'] == state['reputation_count'] == 1
print('Reproduced both defects through original consumer methods; no external runtime I/O.')
Executed output (exit0 checks observed failure signatures, not corrected behavior):
UNCHANGED: expected pings/history/visible/table=1/1/1/1; actual=2/2/2/2
UNCHANGED counters: {'udp': 2} {'fixture-a': 2}
EQUAL_TIMESTAMP_APPEND: expected distinct pings=2; actual pings=3 messages=['first', 'first', 'second']
INCLUSIVE_READER: since=1000 returns ['first', 'second']
ALL_INVALID: ok=True errors=[] counts=[0, 0, 0]
ALL_INVALID sidebar: - status: OK | - agents: 0 | - contracts: 0 | - reputation: 0
VALID_EMPTY: ok=True errors=[] counts=[0, 0, 0]
VALID_EMPTY sidebar: - status: OK | - agents: 0 | - contracts: 0 | - reputation: 0
ONE_INVALID: ok=True errors=[] counts=[1, 0, 1]
ONE_INVALID sidebar: - status: OK | - agents: 1 | - contracts: 0 | - reputation: 1
Reproduced both defects through original consumer methods; no external runtime I/O.
AI assistance disclosed. Bounded novelty searches and local repros do not assert deployed incidents or accepted awards.
Reproduced false healthy-state reporting
Pinned sourceb6960706a6ea1797a63e901c34f06cabd0f7e7a5:
beacon-skill/beacon_skill/dashboard.py
Lines 130 to 171 in b696070
Original fetch/API-poll/sidebar methods with three local HTTP200 responses whose json() raisesValueError produce ok=True, errors=[], counts0/0/0 and sidebarstatusOK. Valid-empty arrays produce the same output. One malformed contracts endpoint plus healthy nonempty agents/reputation retains counts1/0/1 but stillreportsOK/noerror.
Expected: malformed endpoint data is degraded/error state, not a healthy empty network, while valid endpoint data survives. Actual: decode failures are replaced with{} before outer failure handling, leaving okTrue/noerrors. Suggested fix: propagate endpoint-specific decode failures into the established partial-failure/error reporting path without discarding valid endpoints.
Distinct from inclusive inbox polling and already-fixed API baseURL. Symbol/invalidJSON searches matched only unrelated storageJSONLPR829/UDPexamplePR13; no corresponding dashboard decode fix identified.
Reproduction and controls
Python3 stdlib on macOS arm64. Save pinned
dashboard.py,inbox.pyand this script asrepro.pytogether in an isolated directory, runpython3 repro.py. Original reader/poll/display/API/sidebar function ASTs execute unchanged; widgets and HTTP are local fakes. Inbox is a temporary JSONL fixture; known-key/state seams return empty values or no-op. No Textual app, UDP, quick-send, identities/keys, ~/.beacon, live API, account or production writes.Executed output (exit0 checks observed failure signatures, not corrected behavior):
AI assistance disclosed. Bounded novelty searches and local repros do not assert deployed incidents or accepted awards.