Files
Codex Local bf1233d5df
ci / verify (push) Canceled after 0s
feat: expand companion platform, device controls, and memoir workflows
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
2026-10-08 10:06:44 +08:00

52 lines
4.1 KiB
Python

"""COM6-only fixed-sentence smoke test; retain numeric/audio-state evidence only."""
import datetime,json,pathlib,re,serial,subprocess,time
probe = """
import json,subprocess
p=json.loads(subprocess.check_output(['docker','inspect','data-terminal-cloud-postgres-1']))[0]
e=dict(x.split('=',1) for x in p['Config']['Env'] if '=' in x)
q=\"SELECT json_build_object('bound',(SELECT count(*) FROM device_binding WHERE device_id=d.id AND unbound_at IS NULL),'busy',EXISTS(SELECT 1 FROM call_session WHERE device_id=d.id AND call_state IN ('PREPARING','STARTING','TALKING','STOPPING')) OR EXISTS(SELECT 1 FROM conversation WHERE device_id=d.id AND status NOT IN ('COMPLETED','FAILED','EXPIRED')) OR EXISTS(SELECT 1 FROM fleet_ota WHERE device_id=d.id AND status IN ('pending','accepted'))) FROM device d WHERE public_id='623a4e54-bdc4-4c98-b03e-27267d3ff360' AND factory_device_id='KP01-020026091601' AND status='registered'\"
print(subprocess.check_output(['docker','exec',p['Id'],'psql','-U',e['POSTGRES_USER'],'-d',e['POSTGRES_DB'],'-At','-v','ON_ERROR_STOP=1','-c',q],text=True).strip())
"""
result=subprocess.run(['ssh','-i','E:/Codex/story/.local-evidence/account-reset-18642041700-20260916/migration-key.pem','-o','BatchMode=yes','-o','ConnectTimeout=10','root@82.157.201.114','python3 -'],input=probe,text=True,capture_output=True,check=True)
state=json.loads(result.stdout)
if state['busy'] or state['bound']!=1:raise SystemExit('COM6 is busy or binding changed; test not started')
port=serial.Serial();port.port='COM6';port.baudrate=115200;port.timeout=.2;port.dtr=False;port.rts=False
port.open()
patterns=[r'RTC diagnostic: .*',r'USB diagnostic: .*',r'chat end acknowledged=\d+',
r'Network diagnostic: sockets=\d+ limit=\d+',
r'mbedtls_net_connect error, return -0x[0-9a-f]+ errno=\d+',
r'platform_conversation_begin failed, ret: -?\d+',r'volc_start failed, ret: -?\d+',
r'PLATFORM_HTTP method=\w+ status=\d+ elapsed_ms=\d+ new_connection=\d+',
r'Failed to allocate \d+ bytes',r'Cannot allocate memory',
r'get rtc config failed',r'engine start failed: -?\d+',r'engine is not in CREATED state',r'bot id is invalid',
r'engine handle\([a-zA-Z0-9()]+\) or bot id\([a-zA-Z0-9()]+\) is NULL',r'rtc instance is NULL',
r'connect failed, https client (?:context|connect) return: -0x[0-9a-f]+',
r'RTC configuration request prepared',
r'Failed to join room: -?\d+',r'Failed to get response from server',
r'webclient POST request failed, response\(-?\d+\) error',
r'RTC config rejected code=[A-Za-z_0-9.]+ fields room=\d user=\d token=\d task=\d',
r'PLAYBACK (?:stats .*|start .*|idle .*|diagnostic sentence requested ret=-?\d+|feeder write failed|queue overflow.*)',
r'DOWNLINK span_ms=.*',r'AUDIO conversation status=-?\d+',r'device_control: state .*',
r'Platform error code: [A-Z_0-9]+',r'Guru Meditation.*',r'Stack canary.*',r'CORRUPT HEAP.*']
allow=re.compile('|'.join('('+p+')' for p in patterns))
lines=[];stopped=False
try:
port.write(b'\ndiag-say\n');start=time.monotonic()
print('COM6 fixed-sentence test started; no transcript captured',flush=True)
diagnosed=False
while time.monotonic()-start<55:
if not diagnosed and time.monotonic()-start>=15:port.write(b'diag-state\n');diagnosed=True
if not stopped and time.monotonic()-start>=40:port.write(b'diag-stop\n');stopped=True
raw=port.readline().decode('utf-8','replace').strip()
found=allow.search(raw)
if found:
line=found.group(0)[:700];lines.append(line);print(line,flush=True)
finally:
if not stopped:port.write(b'diag-stop\n')
port.close()
stamp=datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%dT%H%M%SZ')
path=pathlib.Path('E:/Codex/story/.local-evidence/com6-controls-20260922')/('voice-'+stamp+'.log')
path.write_text('\n'.join(lines)+'\n',encoding='utf-8')
print(json.dumps({'evidence':str(path),'lines':len(lines),'downlink':any(x.startswith('DOWNLINK ') for x in lines),'playback':any(x.startswith('PLAYBACK stats ') for x in lines),'hangup_ack':any('chat end acknowledged=1' in x for x in lines)}),flush=True)