export type BusReceipt = { id: string; eventType: string; subject: string; source: 'weed-sim' | 'agent' | 'system'; createdAt: string; payload: Record; }; export type BusSignal = { schema: 'observer_bus.signal/v1'; id: string; lane: 'continuity' | 'repo' | 'tests' | 'filesystem' | 'runtime' | 'space' | 'security' | 'workflow' | 'custom' | 'receipt'; severity: 'info' | 'warn' | 'error'; priority: number; title: string; message: string; timestamp: string; route: { command: string; path: string; method: 'GET' | 'POST'; }; ack: { state: 'new' | 'acknowledged'; updatedAt: string | null; note: string | null; }; detail: Record; }; export type BusInbox = { schema: 'observer_bus.signal_inbox/v1'; count: number; lanes: string[]; task_list: Array<{ rank: number; priority: number; lane: string; title: string; command: string; path: string; why: string; }>; signals: BusSignal[]; notifications: BusSignal[]; }; export const WEED_SIM_FACILITIES = [ { key: 'weedsim.inventory', label: 'Inventory', method: 'GET', path: '/api/inventory', risk: 'inspect' }, { key: 'weedsim.load_starters', label: 'Load Starters', method: 'POST', path: '/api/inventory/starter', risk: 'mutating' }, { key: 'weedsim.grow', label: 'Grow', method: 'POST', path: '/api/seed/{id}/grow', risk: 'mutating' }, { key: 'weedsim.breed', label: 'Breed', method: 'POST', path: '/api/breed', risk: 'mutating' }, { key: 'weedsim.clone', label: 'Clone', method: 'POST', path: '/api/clone', risk: 'mutating' }, { key: 'weedsim.germplasm', label: 'Germplasm', method: 'GET', path: '/api/lab/germplasm', risk: 'inspect' }, { key: 'weedsim.predict_cross', label: 'Predict Cross', method: 'POST', path: '/api/lab/predict-cross', risk: 'inspect' }, { key: 'weedsim.newick', label: 'Newick Export', method: 'GET', path: '/api/lab/newick', risk: 'inspect' }, { key: 'weedsim.agent_link', label: 'Agent Control', method: 'POST', path: '/api/agent-link/call', risk: 'scoped' }, { key: 'weedsim.market.listings', label: 'Clone Exchange Listings', method: 'GET', path: '/api/market/listings', risk: 'inspect' }, { key: 'weedsim.market.requests', label: 'Genetics Requests', method: 'GET', path: '/api/market/requests', risk: 'inspect' }, { key: 'weedsim.market.request', label: 'Create Genetics Request', method: 'POST', path: '/api/market/requests', risk: 'mutating' }, { key: 'weedsim.market.offer', label: 'Clone Exchange Offer', method: 'POST', path: '/api/market/offers', risk: 'escrow' }, { key: 'weedsim.passport', label: 'Seed Passport', method: 'GET', path: '/api/passport/{seedId}', risk: 'inspect' }, { key: 'weedsim.leaderboard', label: 'Leaderboard', method: 'GET', path: '/api/leaderboard', risk: 'inspect' }, ] as const; export function signalFromReceipt(receipt: BusReceipt): BusSignal { return { schema: 'observer_bus.signal/v1', id: `sig_${receipt.id}`, lane: 'receipt', severity: 'info', priority: 30, title: `Receipt: ${receipt.eventType}`, message: receipt.subject, timestamp: receipt.createdAt, route: { command: 'receipts', path: '/api/bus/receipts', method: 'GET', }, ack: { state: 'new', updatedAt: null, note: null, }, detail: receipt.payload, }; } export function inboxFromReceipts(receipts: BusReceipt[]): BusInbox { const signals = receipts.slice(0, 20).map(signalFromReceipt); return { schema: 'observer_bus.signal_inbox/v1', count: signals.length, lanes: [...new Set(signals.map((signal) => signal.lane))], task_list: signals.map((signal, index) => ({ rank: index + 1, priority: signal.priority, lane: signal.lane, title: signal.title, command: signal.route.command, path: signal.route.path, why: signal.message, })), signals, notifications: signals, }; }