File size: 3,981 Bytes
1a343cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
export type BusReceipt = {
  id: string;
  eventType: string;
  subject: string;
  source: 'weed-sim' | 'agent' | 'system';
  createdAt: string;
  payload: Record<string, unknown>;
};

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<string, unknown>;
};

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,
  };
}