Skip to content

Commit 67430f8

Browse files
committed
feat(vibee-v10): Cycle 47 REAL — expanded .vibee specs with implementation blocks
- tri_economy_core.vibee: 70→186 lines (8 behaviors, atomic operations) - reward_distribution.vibee: 67→242 lines (8 behaviors, scoring algorithm) - peer_ranking.vibee: 65→276 lines (8 behaviors, Elo-like ranking) - economy_dashboard.vibee: 68→306 lines (9 behaviors, dashboard formatting) Total: 266→1010 lines (+279% expansion) Generated: 1620 LOC across 4 modules VIBEE-first: specs → tri_gen → code (no hand-editing .zig)
1 parent 3df5861 commit 67430f8

File tree

4 files changed

+772
-28
lines changed

4 files changed

+772
-28
lines changed

specs/tri/cycle46/economy_dashboard.vibee

Lines changed: 245 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ types:
1515
total_peers: Int
1616
reward_rate_per_hour: Float
1717
next_payout_time: Int
18+
current_tier: String
19+
tier_multiplier: Float
20+
stake_amount: Int
21+
total_earned: Int
1822

1923
PeerEconomyInfo:
2024
fields:
@@ -23,42 +27,280 @@ types:
2327
score: Float
2428
triples_stored: Int
2529
rewards_earned: Int
30+
rank: Int
31+
uptime_ratio: Float
2632

2733
DashboardUpdate:
2834
fields:
2935
metrics: EconomyMetrics
3036
leaderboard: List<PeerEconomyInfo>
3137
recent_transactions: List<String>
3238
timestamp: Int
39+
update_id: Int
3340

3441
AlertThreshold:
3542
fields:
3643
min_balance: Int
3744
max_unclaimed_hours: Int
3845
min_rank: Int
46+
alert_on_tier_change: Bool
47+
alert_on_large_payment: Bool
48+
large_payment_threshold: Int
49+
50+
Alert:
51+
fields:
52+
alert_type: String
53+
severity: String
54+
message: String
55+
timestamp: Int
56+
data: String
57+
58+
EarningsProjection:
59+
fields:
60+
period_24h: Int
61+
period_7d: Int
62+
period_30d: Int
63+
based_on_hours: Float
64+
confidence: String
3965

4066
behaviors:
4167
- name: get_metrics
42-
given: wallet address
68+
given: wallet address and leaderboard
4369
when: requesting dashboard data
4470
then: returns EconomyMetrics with current state
71+
implementation: |
72+
pub fn getMetrics(allocator: Allocator, wallet: Wallet, leaderboard: Leaderboard, contribution: Contribution) !EconomyMetrics {
73+
// Find peer rank
74+
var rank: usize = 0;
75+
var tier: []const u8 = "Basic";
76+
var multiplier: f64 = 1.0;
77+
78+
for (leaderboard.rankings) |r| {
79+
if (std.mem.eql(u8, r.peer_id, wallet.address)) {
80+
rank = r.rank;
81+
tier = r.tier;
82+
multiplier = getTierMultiplier(r.score);
83+
break;
84+
}
85+
}
86+
87+
// Calculate reward rate based on contribution
88+
const hourly_rate = calculateHourlyRate(contribution, multiplier);
89+
90+
// Next payout is every 24 hours from last claim
91+
const next_payout = wallet.last_activity + (24 * 3600);
92+
93+
return .{
94+
.my_wallet_balance = wallet.balance_wei,
95+
.pending_rewards = wallet.pending_rewards,
96+
.current_rank = @intCast(rank),
97+
.total_peers = leaderboard.total_peers,
98+
.reward_rate_per_hour = hourly_rate,
99+
.next_payout_time = next_payout,
100+
.current_tier = try allocator.dupe(u8, tier),
101+
.tier_multiplier = multiplier,
102+
.stake_amount = wallet.stake_amount,
103+
.total_earned = wallet.total_earned,
104+
};
105+
}
106+
107+
fn calculateHourlyRate(contrib: Contribution, multiplier: f64) f64 {
108+
var base: f64 = 0;
109+
// Storage reward per hour
110+
base += @as(f64, @floatFromInt(contrib.triples_stored)) / 1000;
111+
// Retrieval reward per hour
112+
base += @as(f64, @floatFromInt(contrib.triples_retrieved)) / 500;
113+
// Uptime bonus
114+
const uptime_hours = @as(f64, @floatFromInt(contrib.uptime_seconds)) / 3600;
115+
base += uptime_hours * 0.1;
116+
return base * multiplier;
117+
}
118+
119+
fn getTierMultiplier(score: f64) f64 {
120+
return if (score >= 90) 2.0
121+
else if (score >= 75) 1.5
122+
else if (score >= 60) 1.2
123+
else if (score >= 40) 1.0
124+
else 0.8;
125+
}
45126

46127
- name: format_dashboard_update
47128
given: metrics and leaderboard
48129
when: preparing for Swarm Watch display
49130
then: returns formatted DashboardUpdate
131+
implementation: |
132+
pub fn formatDashboardUpdate(allocator: Allocator, metrics: EconomyMetrics, leaderboard: Leaderboard, update_id: i64) !DashboardUpdate {
133+
// Get top 10 peers
134+
const top_n = @min(10, leaderboard.rankings.len);
135+
136+
var peer_infos = try std.ArrayList(PeerEconomyInfo).initCapacity(allocator, top_n);
137+
defer peer_infos.deinit();
138+
139+
for (leaderboard.rankings[0..top_n]) |r| {
140+
try peer_infos.append(.{
141+
.peer_id = r.peer_id,
142+
.tier = r.tier,
143+
.score = r.score,
144+
.triples_stored = 0, // Would come from Contribution data
145+
.rewards_earned = 0, // Would come from wallet data
146+
.rank = r.rank,
147+
.uptime_ratio = 0, // Would come from stats
148+
});
149+
}
150+
151+
return .{
152+
.metrics = metrics,
153+
.leaderboard = try allocator.dupe(PeerEconomyInfo, peer_infos.items),
154+
.recent_transactions = &[_][]const u8{}, // Empty for now
155+
.timestamp = std.time.timestamp(),
156+
.update_id = @intCast(update_id),
157+
};
158+
}
50159

51160
- name: check_alerts
52161
given: metrics and thresholds
53162
when: checking if alert needed
54163
then: returns alert list if thresholds exceeded
164+
implementation: |
165+
pub fn checkAlerts(allocator: Allocator, metrics: EconomyMetrics, thresholds: AlertThreshold) ![]Alert {
166+
var alerts = std.ArrayList(Alert).init(allocator);
167+
defer alerts.deinit();
168+
169+
// Low balance alert
170+
if (metrics.my_wallet_balance < thresholds.min_balance) {
171+
try alerts.append(.{
172+
.alert_type = "low_balance",
173+
.severity = "warning",
174+
.message = try std.fmt.allocPrint(allocator, "Balance low: {d} TRI", .{metrics.my_wallet_balance}),
175+
.timestamp = std.time.timestamp(),
176+
.data = "",
177+
});
178+
}
179+
180+
// Unclaimed rewards alert
181+
const unclaimed_hours = @as(f64, @floatFromInt(metrics.pending_rewards)) / @max(metrics.reward_rate_per_hour, 0.001);
182+
if (unclaimed_hours > @as(f64, @floatFromInt(thresholds.max_unclaimed_hours))) {
183+
try alerts.append(.{
184+
.alert_type = "unclaimed_rewards",
185+
.severity = "info",
186+
.message = try std.fmt.allocPrint(allocator, "{d:.1} hours of unclaimed rewards", .{unclaimed_hours}),
187+
.timestamp = std.time.timestamp(),
188+
.data = "",
189+
});
190+
}
191+
192+
// Rank drop alert
193+
if (metrics.current_rank > thresholds.min_rank) {
194+
try alerts.append(.{
195+
.alert_type = "rank_drop",
196+
.severity = "warning",
197+
.message = try std.fmt.allocPrint(allocator, "Rank dropped to #{d}", .{metrics.current_rank}),
198+
.timestamp = std.time.timestamp(),
199+
.data = "",
200+
});
201+
}
202+
203+
return allocator.dupe(Alert, alerts.items);
204+
}
55205

56206
- name: get_earnings_projection
57-
given: current stats
207+
given: current stats and rate
58208
when: projecting future earnings
59209
then: returns estimated rewards for 24h/7d/30d
210+
implementation: |
211+
pub fn getEarningsProjection(hourly_rate: f64, hours_sampled: f64) EarningsProjection {
212+
const confidence = if (hours_sampled >= 168) "high" // 1 week
213+
else if (hours_sampled >= 24) "medium"
214+
else "low";
215+
216+
return .{
217+
.period_24h = @floatToInt(i64, @floor(hourly_rate * 24)),
218+
.period_7d = @floatToInt(i64, @floor(hourly_rate * 24 * 7)),
219+
.period_30d = @floatToInt(i64, @floor(hourly_rate * 24 * 30)),
220+
.based_on_hours = hours_sampled,
221+
.confidence = confidence,
222+
};
223+
}
60224

61225
- name: notify_balance_change
62-
given: wallet and amount
226+
given: wallet and amount and thresholds
63227
when: balance changes significantly
64228
then: triggers Telegram notification if enabled
229+
implementation: |
230+
pub fn notifyBalanceChange(allocator: Allocator, wallet: Wallet, amount: i64, thresholds: AlertThreshold) !?[]const u8 {
231+
if (!thresholds.alert_on_large_payment) return null;
232+
if (@abs(amount) < thresholds.large_payment_threshold) return null;
233+
234+
const emoji = if (amount > 0) "🟡" else "🔴";
235+
const action = if (amount > 0) "received" else "sent";
236+
237+
const message = try std.fmt.allocPrint(allocator,
238+
\\{s} Balance Update
239+
\\Amount: {d} TRI {s}
240+
\\New Balance: {d} TRI
241+
\\Tier: {s}
242+
, .{ emoji, @abs(amount), action, wallet.balance_wei, "Basic" });
243+
244+
// Send to Telegram
245+
// TODO: actual Telegram integration
246+
_ = sendTelegramNotification(message);
247+
248+
return message;
249+
}
250+
251+
- name: format_leaderboard_entry
252+
given: peer ranking info
253+
when: formatting single leaderboard entry
254+
then: returns formatted string for display
255+
implementation: |
256+
pub fn formatLeaderboardEntry(allocator: Allocator, info: PeerEconomyInfo) ![]const u8 {
257+
const tier_emoji = getTierEmoji(info.tier);
258+
return try std.fmt.allocPrint(allocator,
259+
"{s} #{d: >3} | {s: <12} | Score: {d: >5.1} | Stored: {d: >6}",
260+
.{ tier_emoji, info.rank, info.peer_id, info.score, info.triples_stored }
261+
);
262+
}
263+
264+
fn getTierEmoji(tier: []const u8) []const u8 {
265+
return if (std.mem.eql(u8, tier, "Elite")) "👑"
266+
else if (std.mem.eql(u8, tier, "Gold")) "🥇"
267+
else if (std.mem.eql(u8, tier, "Silver")) "🥈"
268+
else if (std.mem.eql(u8, tier, "Bronze")) "🥉"
269+
else "⚪";
270+
}
271+
272+
- name: create_dashboard_summary
273+
given: metrics and projection
274+
when: creating summary widget
275+
then: returns formatted multi-line summary
276+
implementation: |
277+
pub fn createDashboardSummary(allocator: Allocator, metrics: EconomyMetrics, projection: EarningsProjection) ![]const u8 {
278+
return try std.fmt.allocPrint(allocator,
279+
\\╔════════════════════════════════════════╗
280+
\\║ TRI ECONOMY DASHBOARD ║
281+
\\╠════════════════════════════════════════╣
282+
\\║ Balance: {d: >15} TRI ║
283+
\\║ Pending: {d: >15} TRI ║
284+
\\║ Rank: #{d: >14} ║
285+
\\║ Tier: {s: <15} ║
286+
\\║ Multiplier: {d: >15.1f}x ║
287+
\\║ Rate/h: {d: >15.2} TRI ║
288+
\\╠────────────────────────────────────────╣
289+
\\║ Projections ({s: >6} confidence): ║
290+
\\║ 24h: +{d: >12} TRI ║
291+
\\║ 7d: +{d: >12} TRI ║
292+
\\║ 30d: +{d: >12} TRI ║
293+
\\╚════════════════════════════════════════╝
294+
, .{
295+
metrics.my_wallet_balance,
296+
metrics.pending_rewards,
297+
metrics.current_rank,
298+
metrics.current_tier,
299+
metrics.tier_multiplier,
300+
metrics.reward_rate_per_hour,
301+
projection.confidence,
302+
projection.period_24h,
303+
projection.period_7d,
304+
projection.period_30d,
305+
});
306+
}

0 commit comments

Comments
 (0)