personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

convey/speakers: migrate owner onboarding mutations to wave 0 primitives (wave 2)

Move the owner status and choice flows to apiJson.
Keep owner-banner errors visible and log failures for telemetry.

+13 -11
+13 -11
apps/speakers/workspace.html
··· 1257 1257 }); 1258 1258 1259 1259 function checkOwnerStatus() { 1260 - fetch('/app/speakers/api/owner/status') 1261 - .then(r => r.json()) 1260 + window.apiJson('/app/speakers/api/owner/status') 1262 1261 .then(data => { 1263 1262 if (data.status === 'needs_detection') { 1264 1263 hideDiscovery(); 1265 1264 renderOwnerBanner('Analyzing voice patterns...'); 1266 1265 if (!ownerDetectionInFlight) { 1267 1266 ownerDetectionInFlight = true; 1268 - fetch('/app/speakers/api/owner/detect', { method: 'POST' }) 1269 - .then(r => r.json()) 1267 + window.apiJson('/app/speakers/api/owner/detect', { method: 'POST' }) 1270 1268 .then(() => { 1271 1269 ownerDetectionInFlight = false; 1272 1270 checkOwnerStatus(); 1273 1271 }) 1274 - .catch(() => { 1272 + .catch((err) => { 1275 1273 ownerDetectionInFlight = false; 1276 - hideOwnerBanner(); 1274 + renderOwnerBanner(`Couldn't analyze voice patterns — ${resolveSpeakerError(err)}`); 1275 + window.logError(err, { context: 'speakers: owner detect failed' }); 1277 1276 }); 1278 1277 } 1279 1278 return; ··· 1294 1293 hideOwnerBanner(); 1295 1294 checkDiscovery(); 1296 1295 }) 1297 - .catch(() => { 1296 + .catch((err) => { 1297 + ownerDetectionInFlight = false; 1298 1298 hideDiscovery(); 1299 - hideOwnerBanner(); 1299 + renderOwnerBanner(`Couldn't load owner status — ${resolveSpeakerError(err)}`); 1300 + window.logError(err, { context: 'speakers: checkOwnerStatus failed' }); 1300 1301 }); 1301 1302 } 1302 1303 ··· 1354 1355 1355 1356 function submitOwnerChoice(path) { 1356 1357 ownerBanner.querySelectorAll('button').forEach(btn => { btn.disabled = true; }); 1357 - fetch(path, { method: 'POST' }) 1358 - .then(r => r.json()) 1358 + window.apiJson(path, { method: 'POST' }) 1359 1359 .then(() => { 1360 1360 checkOwnerStatus(); 1361 1361 }) 1362 - .catch(() => { 1362 + .catch((err) => { 1363 1363 ownerBanner.querySelectorAll('button').forEach(btn => { btn.disabled = false; }); 1364 + renderOwnerBanner(resolveSpeakerError(err)); 1365 + window.logError(err, { context: 'speakers: submitOwnerChoice failed' }); 1364 1366 }); 1365 1367 } 1366 1368