Implement Book of Owners and license system
- Add ownership ledger with public aliases and private identity mapping - Create license transaction tracking and upgrade automation - Implement validation system for SC/SK awards based on licenses - Set up privacy protection with .gitignore for sensitive data - Initialize founding entrepreneur as owner #001 - Ready for founding work audit processmaster
parent
0b777d311f
commit
5738af29df
|
@ -0,0 +1,7 @@
|
||||||
|
# Privacy Protection - Never commit personal data
|
||||||
|
ownership/identity-mapping.csv
|
||||||
|
**/identity-mapping.csv
|
||||||
|
|
||||||
|
# Backup files
|
||||||
|
*.backup
|
||||||
|
*.bak
|
|
@ -0,0 +1,4 @@
|
||||||
|
timestamp,type,amount,from,to,reference,description,approver,phase,evidence_link
|
||||||
|
# Smartup Credits (SC) Transaction Ledger
|
||||||
|
# Format: ISO timestamp, SC/REDEEM, amount, from_user, to_user, task_id, description, approver, phase, link_to_work
|
||||||
|
# Example: 2025-01-15T10:30:00Z,SC,50,,alice,task-123,Backend API completion,bob,validation,https://forgejo.../issues/123
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
timestamp,type,amount,from,to,reference,description,awarded_by,category,evidence_link
|
||||||
|
# Social Karma (SK) Transaction Ledger
|
||||||
|
# Format: ISO timestamp, KARMA/DECAY, amount, from_user, to_user, event_id, description, awarder, category, evidence
|
||||||
|
# Example: 2025-01-15T11:00:00Z,KARMA,10,,alice,pr-456,Excellent code review for mesh protocol,bob,code_review,https://forgejo.../pull/456
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
timestamp,event_type,amount_eur_delta,total_eur_balance,sc_outstanding,sc_liability_eur,ratio,notes,reference
|
||||||
|
# Treasury Balance and SC Liability Tracking
|
||||||
|
# Format: ISO timestamp, event_type, EUR_change, total_EUR, total_SC, SC_value_EUR, ratio, notes, reference
|
||||||
|
# The 3x Rule: sc_liability_eur must be ≤ 3x total_eur_balance
|
||||||
|
2025-01-15T00:00:00Z,INIT,0,0,0,0,0.0,Treasury initialized - Smartup Zero launch,system-init
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
owner_id,display_name,license_type,license_date,current_sk,voting_weight,status,last_updated
|
||||||
|
001,robbert_founder,work,2025-08-04T14:37:16.470130Z,0,1.00,active,2025-08-04T14:37:16.470130Z
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
timestamp,owner_id,transaction_type,from_license,to_license,payment_eur,upgrade_reason,reference,approver
|
||||||
|
2025-08-04T14:37:16.470130Z,001,FOUNDER,,work,0,founding_entrepreneur,system-init,smartup-zero-launch
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Smartup Credits (SC) Rate Structure
|
||||||
|
# 1 SC = 1 EUR claim on treasury
|
||||||
|
# Updated: 2025-01-15
|
||||||
|
|
||||||
|
# Standard Task Rates
|
||||||
|
task_rates:
|
||||||
|
small_task: 25 # 1-2 hours work
|
||||||
|
medium_task: 50 # 3-4 hours work
|
||||||
|
large_task: 100 # 5-8 hours work
|
||||||
|
complex_task: 200 # 1-2 days work
|
||||||
|
|
||||||
|
# ADM Triangle Split (Attacker/Defender Model)
|
||||||
|
adm_split:
|
||||||
|
attacker_percentage: 90 # Senior contributor doing main work
|
||||||
|
defender_percentage: 10 # Junior contributor learning + reviewing
|
||||||
|
midfielder_percentage: 0 # Engelbot handles automatically
|
||||||
|
|
||||||
|
# Founding Work Audit Rates (Retroactive)
|
||||||
|
founding_work_rates:
|
||||||
|
research_hour: 25 # Historical R&D and investigation
|
||||||
|
planning_hour: 25 # Business plan and strategy creation
|
||||||
|
coding_hour: 30 # Technical development and prototyping
|
||||||
|
writing_hour: 20 # Documentation and content creation
|
||||||
|
governance_hour: 25 # Smartup model design and legal setup
|
||||||
|
|
||||||
|
# Special Contribution Rates
|
||||||
|
special_rates:
|
||||||
|
team_captain_monthly: 100 # Monthly leadership bonus
|
||||||
|
mission_leader_bonus: 50 # Per completed objective
|
||||||
|
emergency_fix: 150 # Critical bug fixes
|
||||||
|
community_building: 75 # Outreach and recruitment
|
||||||
|
|
||||||
|
# Phase-Based Multipliers
|
||||||
|
phase_multipliers:
|
||||||
|
validation: 1.0 # Standard rates during proof phase
|
||||||
|
design: 1.1 # 10% bonus during intensive design
|
||||||
|
production: 1.2 # 20% bonus during crunch time
|
||||||
|
organization: 1.0 # Back to standard for stable operations
|
||||||
|
|
||||||
|
# Treasury Protection Rules
|
||||||
|
treasury_rules:
|
||||||
|
max_outstanding_multiplier: 3 # Outstanding SC ≤ 3x cash treasury
|
||||||
|
founding_work_cap: 10000 # Maximum retroactive SC for entrepreneur
|
||||||
|
daily_mint_limit: 500 # Max SC mintable per person per day
|
||||||
|
requires_defender_approval: true
|
|
@ -0,0 +1,70 @@
|
||||||
|
# Social Karma (SK) Award Structure
|
||||||
|
# Non-transferable reputation currency
|
||||||
|
# Updated: 2025-01-15
|
||||||
|
|
||||||
|
# SK Award Categories
|
||||||
|
karma_awards:
|
||||||
|
# Code & Technical Quality
|
||||||
|
code_review: 5 # Reviewing PRs and providing feedback
|
||||||
|
bug_find: 10 # Finding and reporting bugs
|
||||||
|
documentation: 15 # Writing guides and technical docs
|
||||||
|
|
||||||
|
# Community Building
|
||||||
|
mentoring_session: 10 # One-on-one help with newcomers
|
||||||
|
mentoring_weekly: 5 # Ongoing mentorship (awarded weekly)
|
||||||
|
conflict_resolution: 25 # Successfully mediating disputes
|
||||||
|
onboarding_help: 8 # Helping new members navigate
|
||||||
|
|
||||||
|
# Governance & Leadership
|
||||||
|
governance_participation: 20 # Leading discussions in General Forum
|
||||||
|
proposal_accepted: 20 # Successful proposals that pass votes
|
||||||
|
meeting_facilitation: 15 # Running team meetings effectively
|
||||||
|
cross_team_coordination: 12 # Bridging different teams
|
||||||
|
|
||||||
|
# Mission Completion
|
||||||
|
objective_completion: 15 # Completing mission objectives
|
||||||
|
deadline_hit: 10 # Meeting critical deadlines
|
||||||
|
quality_delivery: 12 # Exceptional work quality recognition
|
||||||
|
|
||||||
|
# SK Privilege Thresholds
|
||||||
|
privilege_thresholds:
|
||||||
|
propose_in_forum: 50 # Can create binding vote proposals
|
||||||
|
apply_team_captain: 100 # Eligible for team leadership roles
|
||||||
|
lead_missions: 200 # Can be assigned as Mission Leader
|
||||||
|
join_leadership_team: 500 # Eligible for Leadership Team
|
||||||
|
|
||||||
|
# Voting Weight (SK enhances but doesn't replace democracy)
|
||||||
|
voting_weight:
|
||||||
|
base_vote: 1.0 # Everyone gets 1 vote regardless
|
||||||
|
sk_bonus_max: 1.5 # Maximum vote weight with high SK
|
||||||
|
sk_bonus_threshold: 500 # SK needed for max voting bonus
|
||||||
|
calculation: "min(1.5, 1 + (sk_points / 1000))"
|
||||||
|
|
||||||
|
# SK Decay Mechanism (prevents founder entrenchment)
|
||||||
|
decay_rules:
|
||||||
|
monthly_decay_rate: 0.10 # 10% monthly decay
|
||||||
|
minimum_floor: 0 # Can decay to zero (stay active!)
|
||||||
|
grace_period_days: 30 # No decay for first month after earning
|
||||||
|
activity_bonus: 5 # Monthly bonus for active participation
|
||||||
|
|
||||||
|
# Anti-Gaming Measures
|
||||||
|
validation_rules:
|
||||||
|
cannot_buy: true # No amount of money gets you SK
|
||||||
|
cannot_transfer: true # Your reputation is yours alone
|
||||||
|
cannot_hoard: true # Use influence or lose it to decay
|
||||||
|
peer_review_required: true # SK awards need defender confirmation
|
||||||
|
|
||||||
|
# SK Sources (who can award SK)
|
||||||
|
award_sources:
|
||||||
|
peer_recognition: true # Team members award each other
|
||||||
|
captain_awards: true # Team Captains can award their team
|
||||||
|
leadership_awards: true # Leadership Team for exceptional cases
|
||||||
|
community_votes: true # General Forum for major contributions
|
||||||
|
automated_systems: false # No bot-awarded SK (human judgment only)
|
||||||
|
|
||||||
|
# Monthly SK Budget (prevents inflation)
|
||||||
|
team_budgets:
|
||||||
|
per_team_monthly: 200 # Each team can award 200 SK/month
|
||||||
|
leadership_monthly: 500 # Leadership Team additional budget
|
||||||
|
community_monthly: 300 # General Forum discretionary awards
|
||||||
|
rollover_limit: 0.5 # Unused budget 50% carries to next month
|
|
@ -0,0 +1,105 @@
|
||||||
|
# License System Policies
|
||||||
|
# Updated: 2025-01-15
|
||||||
|
|
||||||
|
# License Types and Capabilities
|
||||||
|
license_capabilities:
|
||||||
|
campaign:
|
||||||
|
can_earn_sk: true
|
||||||
|
can_earn_sc: false
|
||||||
|
sk_categories: ["community_building", "governance_participation", "mentoring_help"]
|
||||||
|
max_daily_sk: 25
|
||||||
|
voting_rights: true
|
||||||
|
forum_access: "1_general_forum"
|
||||||
|
|
||||||
|
watch:
|
||||||
|
can_earn_sk: true
|
||||||
|
can_earn_sc: false
|
||||||
|
sk_categories: ["all_except_leadership"]
|
||||||
|
max_daily_sk: 50
|
||||||
|
voting_rights: true
|
||||||
|
forum_access: "1_general_forum,limited_2_workplace"
|
||||||
|
|
||||||
|
work:
|
||||||
|
can_earn_sk: true
|
||||||
|
can_earn_sc: true
|
||||||
|
sk_categories: ["all"]
|
||||||
|
max_daily_sk: 100
|
||||||
|
max_daily_sc: 500
|
||||||
|
voting_rights: true
|
||||||
|
forum_access: "all_tiers"
|
||||||
|
|
||||||
|
organizational:
|
||||||
|
can_earn_sk: true
|
||||||
|
can_earn_sc: true
|
||||||
|
sk_categories: ["all"]
|
||||||
|
max_daily_sk: 100
|
||||||
|
max_daily_sc: 500
|
||||||
|
voting_rights: true
|
||||||
|
voting_weight_bonus: 0 # Same as individual, no special treatment
|
||||||
|
forum_access: "all_tiers"
|
||||||
|
|
||||||
|
# Automatic Upgrade Rules
|
||||||
|
upgrade_thresholds:
|
||||||
|
campaign_to_watch:
|
||||||
|
sk_required: 100
|
||||||
|
additional_requirements: []
|
||||||
|
approval_needed: false
|
||||||
|
notification_required: true
|
||||||
|
|
||||||
|
watch_to_work:
|
||||||
|
payment_required: 200 # EUR
|
||||||
|
sk_minimum: 50 # Must demonstrate some engagement
|
||||||
|
approval_needed: false
|
||||||
|
|
||||||
|
work_to_organizational:
|
||||||
|
payment_required: 5000 # EUR
|
||||||
|
sk_minimum: 200 # Must be proven contributor
|
||||||
|
approval_needed: true # Community/Leadership review
|
||||||
|
|
||||||
|
# License Pricing (increases by phase)
|
||||||
|
pricing:
|
||||||
|
validation_phase:
|
||||||
|
campaign: 0
|
||||||
|
watch: 100
|
||||||
|
work: 200
|
||||||
|
organizational: 5000
|
||||||
|
|
||||||
|
design_phase:
|
||||||
|
campaign: 0
|
||||||
|
watch: 200
|
||||||
|
work: 400
|
||||||
|
organizational: 10000
|
||||||
|
|
||||||
|
production_phase:
|
||||||
|
campaign: 0
|
||||||
|
watch: 400
|
||||||
|
work: 800
|
||||||
|
organizational: 20000
|
||||||
|
|
||||||
|
organization_phase:
|
||||||
|
campaign: 0
|
||||||
|
watch: 800
|
||||||
|
work: 1600
|
||||||
|
organizational: 40000
|
||||||
|
|
||||||
|
# Identity and Privacy
|
||||||
|
identity_rules:
|
||||||
|
alias_required: false
|
||||||
|
real_name_public: false
|
||||||
|
can_change_alias: true
|
||||||
|
alias_change_limit: 2 # per year
|
||||||
|
privacy_levels: ["full_public", "alias_only", "anonymous"]
|
||||||
|
|
||||||
|
# Voting Weight Calculation
|
||||||
|
voting_weight:
|
||||||
|
base_weight: 1.0
|
||||||
|
sk_bonus_formula: "min(1.5, 1 + (current_sk / 1000))"
|
||||||
|
max_weight: 1.5
|
||||||
|
organizational_bonus: 0 # No special voting power for big payments
|
||||||
|
|
||||||
|
# Status Management
|
||||||
|
status_rules:
|
||||||
|
inactive_threshold_days: 90 # No activity = inactive status
|
||||||
|
suspension_requires: "leadership_vote"
|
||||||
|
reactivation_requires: "login_activity"
|
||||||
|
permanent_ban_requires: "community_vote"
|
|
@ -0,0 +1,82 @@
|
||||||
|
# Currency Ledger Validation Rules
|
||||||
|
# Ensures system integrity and democratic oversight
|
||||||
|
# Updated: 2025-01-15
|
||||||
|
|
||||||
|
# Transaction Validation
|
||||||
|
transaction_rules:
|
||||||
|
requires_defender_approval: true
|
||||||
|
requires_captain_approval: true # Team Captain must approve team transactions
|
||||||
|
requires_evidence: true # Link to completed work required
|
||||||
|
max_transaction_age_days: 7 # Must be processed within week
|
||||||
|
retroactive_limit_days: 30 # Can't claim SC for work >30 days old
|
||||||
|
|
||||||
|
# Democratic Oversight
|
||||||
|
approval_process:
|
||||||
|
small_transactions_threshold: 100 # SC amounts ≤ 100 need team approval
|
||||||
|
large_transactions_threshold: 200 # SC amounts > 200 need community review
|
||||||
|
founding_work_review_days: 7 # Community review period for founding audit
|
||||||
|
binding_vote_threshold: 3 # Major issues need General Forum vote
|
||||||
|
lazy_consensus_hours: 48 # 48h for community feedback
|
||||||
|
|
||||||
|
# License Integration (Progressive Transparency)
|
||||||
|
license_requirements:
|
||||||
|
campaign_license:
|
||||||
|
can_view_ledger: true
|
||||||
|
can_propose_transactions: false
|
||||||
|
can_approve_transactions: false
|
||||||
|
watch_license:
|
||||||
|
can_view_ledger: true
|
||||||
|
can_propose_transactions: false
|
||||||
|
can_approve_transactions: false
|
||||||
|
work_license:
|
||||||
|
can_view_ledger: true
|
||||||
|
can_propose_transactions: true # Can claim SC for completed tasks
|
||||||
|
can_approve_transactions: false
|
||||||
|
organizational_license:
|
||||||
|
can_view_ledger: true
|
||||||
|
can_propose_transactions: true
|
||||||
|
can_approve_transactions: false # No special approval powers
|
||||||
|
|
||||||
|
# Treasury Protection
|
||||||
|
treasury_validation:
|
||||||
|
max_outstanding_ratio: 3.0 # Outstanding SC ≤ 3x treasury EUR
|
||||||
|
min_treasury_reserve: 1000 # Always keep €1000 emergency reserve
|
||||||
|
redemption_window_trigger: 0.8 # Open redemption at 80% treasury capacity
|
||||||
|
fifo_redemption: true # First earned, first redeemed
|
||||||
|
|
||||||
|
# Quality Assurance
|
||||||
|
quality_rules:
|
||||||
|
requires_task_reference: true # Must link to Forgejo issue/task
|
||||||
|
requires_time_estimate: true # Estimate vs actual hours tracking
|
||||||
|
requires_defender_review: true # Code/work quality confirmation
|
||||||
|
allows_partial_payments: true # Can pay in installments for large tasks
|
||||||
|
|
||||||
|
# Anti-Fraud Measures
|
||||||
|
security_rules:
|
||||||
|
max_daily_sc_per_person: 500 # Prevents gaming
|
||||||
|
requires_captain_countersign: true # Team Captain must approve team payments
|
||||||
|
founder_cap_total: 10000 # Max retroactive SC for any founder
|
||||||
|
community_veto_window: 48 # Hours for community to object
|
||||||
|
permanent_public_record: true # All transactions permanent in git history
|
||||||
|
|
||||||
|
# Integration Rules
|
||||||
|
technical_integration:
|
||||||
|
forgejo_issue_required: true # Must reference actual task
|
||||||
|
element_notification: true # Announce all awards in General Forum
|
||||||
|
engelbot_automation: true # Bot handles routine validations
|
||||||
|
open_collective_sync: true # Treasury sync with OC EU
|
||||||
|
|
||||||
|
# Phase-Specific Rules
|
||||||
|
phase_rules:
|
||||||
|
validation_phase:
|
||||||
|
founding_work_audit: true # Special process for entrepreneur work
|
||||||
|
community_vote_required: true # Major SC awards need approval
|
||||||
|
conservative_rates: true # Start with proven rates
|
||||||
|
design_phase:
|
||||||
|
increased_complexity_bonus: true # Higher rates for complex design work
|
||||||
|
science_team_veto: true # Science team can halt inappropriate awards
|
||||||
|
cross_team_collaboration_bonus: true
|
||||||
|
production_phase:
|
||||||
|
crunch_time_multiplier: 1.2 # 20% bonus during intensive development
|
||||||
|
quality_gates: true # Extra validation for production code
|
||||||
|
user_feedback_integration: true # Bonus for incorporating
|
|
@ -0,0 +1,122 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Currency Ledger Report Generator
|
||||||
|
Creates summary reports for community transparency
|
||||||
|
"""
|
||||||
|
|
||||||
|
import csv
|
||||||
|
import yaml
|
||||||
|
from datetime import datetime
|
||||||
|
import os
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
def generate_sc_summary():
|
||||||
|
"""Generate SC summary report"""
|
||||||
|
print("📊 SMARTUP CREDITS SUMMARY REPORT")
|
||||||
|
print("=" * 40)
|
||||||
|
|
||||||
|
ledger_file = os.path.join(os.path.dirname(__file__), '..', 'ledger', 'smartup-credits', 'transactions.csv')
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(ledger_file, 'r') as f:
|
||||||
|
reader = csv.DictReader(f)
|
||||||
|
|
||||||
|
user_balances = defaultdict(int)
|
||||||
|
total_minted = 0
|
||||||
|
total_redeemed = 0
|
||||||
|
transaction_count = 0
|
||||||
|
|
||||||
|
for row in reader:
|
||||||
|
if row['type'] == 'SC':
|
||||||
|
amount = int(row['amount'])
|
||||||
|
user_balances[row['to']] += amount
|
||||||
|
total_minted += amount
|
||||||
|
transaction_count += 1
|
||||||
|
elif row['type'] == 'REDEEM':
|
||||||
|
amount = int(row['amount'])
|
||||||
|
user_balances[row['from']] -= amount
|
||||||
|
total_redeemed += amount
|
||||||
|
transaction_count += 1
|
||||||
|
|
||||||
|
print(f"Total SC Minted: {total_minted}")
|
||||||
|
print(f"Total SC Redeemed: {total_redeemed}")
|
||||||
|
print(f"SC Outstanding: {total_minted - total_redeemed}")
|
||||||
|
print(f"Total Transactions: {transaction_count}")
|
||||||
|
print(f"Active Contributors: {len([u for u in user_balances if user_balances[u] > 0])}")
|
||||||
|
|
||||||
|
# Top contributors
|
||||||
|
if user_balances:
|
||||||
|
print("\n🏆 TOP SC EARNERS:")
|
||||||
|
sorted_users = sorted(user_balances.items(), key=lambda x: x[1], reverse=True)
|
||||||
|
for i, (user, balance) in enumerate(sorted_users[:5]):
|
||||||
|
if balance > 0:
|
||||||
|
print(f"{i+1}. {user}: {balance} SC")
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("❌ No SC transactions found")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error generating SC report: {e}")
|
||||||
|
|
||||||
|
def generate_treasury_report():
|
||||||
|
"""Generate treasury health report"""
|
||||||
|
print("\n💰 TREASURY HEALTH REPORT")
|
||||||
|
print("=" * 30)
|
||||||
|
|
||||||
|
treasury_file = os.path.join(os.path.dirname(__file__), '..', 'ledger', 'treasury', 'balance.csv')
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(treasury_file, 'r') as f:
|
||||||
|
reader = csv.DictReader(f)
|
||||||
|
rows = list(reader)
|
||||||
|
|
||||||
|
if rows:
|
||||||
|
latest = rows[-1]
|
||||||
|
eur_balance = float(latest['total_eur_balance'])
|
||||||
|
sc_outstanding = int(latest['sc_outstanding'])
|
||||||
|
sc_liability = float(latest['sc_liability_eur'])
|
||||||
|
|
||||||
|
print(f"💶 EUR Treasury: €{eur_balance:,.2f}")
|
||||||
|
print(f"🪙 SC Outstanding: {sc_outstanding:,} SC")
|
||||||
|
print(f"💸 SC Liability: €{sc_liability:,.2f}")
|
||||||
|
|
||||||
|
if eur_balance > 0:
|
||||||
|
coverage_ratio = eur_balance / sc_liability if sc_liability > 0 else float('inf')
|
||||||
|
print(f"📊 Coverage Ratio: {coverage_ratio:.2f}x")
|
||||||
|
|
||||||
|
if coverage_ratio >= 1.0:
|
||||||
|
print("✅ Full SC redemption possible")
|
||||||
|
else:
|
||||||
|
redemption_capacity = int(eur_balance)
|
||||||
|
print(f"⚠️ Partial redemption: €{redemption_capacity:,} available")
|
||||||
|
|
||||||
|
# 3x rule check
|
||||||
|
max_allowed_sc = eur_balance * 3
|
||||||
|
print(f"🛡️ 3x Rule: {sc_outstanding:,} / {max_allowed_sc:,.0f} SC allowed")
|
||||||
|
|
||||||
|
if sc_outstanding <= max_allowed_sc:
|
||||||
|
print("✅ 3x Rule: COMPLIANT")
|
||||||
|
else:
|
||||||
|
print("🚨 3x Rule: VIOLATION")
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("⚠️ Treasury initialized but no balance records")
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("❌ No treasury records found")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error generating treasury report: {e}")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Generate all reports"""
|
||||||
|
print("📈 SMARTUP ZERO FINANCIAL REPORTS")
|
||||||
|
print(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
generate_sc_summary()
|
||||||
|
generate_treasury_report()
|
||||||
|
|
||||||
|
print("\n" + "=" * 50)
|
||||||
|
print("💡 All ledger data is public and auditable in git history")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -0,0 +1,43 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Initialize the founding entrepreneur in Book of Owners
|
||||||
|
This creates the first owner record for Robbert
|
||||||
|
"""
|
||||||
|
|
||||||
|
import csv
|
||||||
|
from datetime import datetime
|
||||||
|
import os
|
||||||
|
|
||||||
|
def initialize_founder():
|
||||||
|
"""Add the founding entrepreneur to Book of Owners"""
|
||||||
|
|
||||||
|
base_path = os.path.join(os.path.dirname(__file__), '..')
|
||||||
|
timestamp = datetime.now().isoformat() + 'Z'
|
||||||
|
|
||||||
|
# Create identity mapping (PRIVATE - not committed)
|
||||||
|
identity_file = os.path.join(base_path, 'ownership', 'identity-mapping.csv')
|
||||||
|
with open(identity_file, 'w', newline='') as f:
|
||||||
|
writer = csv.writer(f)
|
||||||
|
writer.writerow(['owner_id', 'real_name', 'email', 'display_name', 'privacy_level', 'created_date'])
|
||||||
|
writer.writerow(['001', 'Robbert Schep', 'robbert@timeline0.org', 'robbert_founder', 'alias_only', timestamp])
|
||||||
|
|
||||||
|
# Create license transaction record
|
||||||
|
transactions_file = os.path.join(base_path, 'ownership', 'license-transactions.csv')
|
||||||
|
with open(transactions_file, 'w', newline='') as f:
|
||||||
|
writer = csv.writer(f)
|
||||||
|
writer.writerow(['timestamp', 'owner_id', 'transaction_type', 'from_license', 'to_license', 'payment_eur', 'upgrade_reason', 'reference', 'approver'])
|
||||||
|
writer.writerow([timestamp, '001', 'FOUNDER', '', 'work', 0, 'founding_entrepreneur', 'system-init', 'smartup-zero-launch'])
|
||||||
|
|
||||||
|
# Update Book of Owners (PUBLIC)
|
||||||
|
book_file = os.path.join(base_path, 'ownership', 'book-of-owners.csv')
|
||||||
|
with open(book_file, 'w', newline='') as f:
|
||||||
|
writer = csv.writer(f)
|
||||||
|
writer.writerow(['owner_id', 'display_name', 'license_type', 'license_date', 'current_sk', 'voting_weight', 'status', 'last_updated'])
|
||||||
|
writer.writerow(['001', 'robbert_founder', 'work', timestamp, '0', '1.00', 'active', timestamp])
|
||||||
|
|
||||||
|
print("✅ Founding entrepreneur initialized in Book of Owners")
|
||||||
|
print("📝 Identity mapping created (private file)")
|
||||||
|
print("📊 Ready for founding work audit process")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
initialize_founder()
|
|
@ -0,0 +1,203 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Book of Owners Management Script
|
||||||
|
Handles license purchases, upgrades, and validation
|
||||||
|
"""
|
||||||
|
|
||||||
|
import csv
|
||||||
|
import yaml
|
||||||
|
from datetime import datetime
|
||||||
|
import os
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
class OwnershipManager:
|
||||||
|
def __init__(self):
|
||||||
|
self.base_path = os.path.join(os.path.dirname(__file__), '..')
|
||||||
|
self.load_policies()
|
||||||
|
|
||||||
|
def load_policies(self):
|
||||||
|
"""Load license policies"""
|
||||||
|
with open(os.path.join(self.base_path, 'policies', 'license-policies.yml'), 'r') as f:
|
||||||
|
self.policies = yaml.safe_load(f)
|
||||||
|
|
||||||
|
def generate_owner_id(self):
|
||||||
|
"""Generate unique owner ID"""
|
||||||
|
# Simple 3-digit incremental ID (could be more sophisticated)
|
||||||
|
book_file = os.path.join(self.base_path, 'ownership', 'book-of-owners.csv')
|
||||||
|
try:
|
||||||
|
with open(book_file, 'r') as f:
|
||||||
|
reader = csv.DictReader(f)
|
||||||
|
existing_ids = [int(row['owner_id']) for row in reader if row['owner_id'].isdigit()]
|
||||||
|
next_id = max(existing_ids) + 1 if existing_ids else 1
|
||||||
|
return f"{next_id:03d}"
|
||||||
|
except (FileNotFoundError, ValueError):
|
||||||
|
return "001"
|
||||||
|
|
||||||
|
def add_new_owner(self, real_name, email, display_name, license_type, payment_eur=0, privacy_level="alias_only"):
|
||||||
|
"""Add new owner to the system"""
|
||||||
|
owner_id = self.generate_owner_id()
|
||||||
|
timestamp = datetime.now().isoformat() + 'Z'
|
||||||
|
|
||||||
|
# Add to identity mapping (private)
|
||||||
|
identity_file = os.path.join(self.base_path, 'ownership', 'identity-mapping.csv')
|
||||||
|
with open(identity_file, 'a', newline='') as f:
|
||||||
|
writer = csv.writer(f)
|
||||||
|
writer.writerow([owner_id, real_name, email, display_name, privacy_level, timestamp])
|
||||||
|
|
||||||
|
# Add to license transactions
|
||||||
|
self.record_license_transaction(owner_id, "PURCHASE", "", license_type, payment_eur, "initial_purchase")
|
||||||
|
|
||||||
|
# Update book of owners
|
||||||
|
self.update_book_of_owners(owner_id, display_name, license_type)
|
||||||
|
|
||||||
|
print(f"✅ New owner added: {display_name} ({owner_id}) - {license_type} license")
|
||||||
|
return owner_id
|
||||||
|
|
||||||
|
def record_license_transaction(self, owner_id, transaction_type, from_license, to_license, payment_eur, reason, reference="manual", approver="system"):
|
||||||
|
"""Record license change in transaction log"""
|
||||||
|
timestamp = datetime.now().isoformat() + 'Z'
|
||||||
|
|
||||||
|
transactions_file = os.path.join(self.base_path, 'ownership', 'license-transactions.csv')
|
||||||
|
with open(transactions_file, 'a', newline='') as f:
|
||||||
|
writer = csv.writer(f)
|
||||||
|
writer.writerow([timestamp, owner_id, transaction_type, from_license, to_license, payment_eur, reason, reference, approver])
|
||||||
|
|
||||||
|
def update_book_of_owners(self, owner_id, display_name, license_type, current_sk=0, status="active"):
|
||||||
|
"""Update current book of owners record"""
|
||||||
|
timestamp = datetime.now().isoformat() + 'Z'
|
||||||
|
voting_weight = min(1.5, 1 + (current_sk / 1000))
|
||||||
|
|
||||||
|
book_file = os.path.join(self.base_path, 'ownership', 'book-of-owners.csv')
|
||||||
|
|
||||||
|
# Read existing records
|
||||||
|
records = []
|
||||||
|
try:
|
||||||
|
with open(book_file, 'r') as f:
|
||||||
|
reader = csv.DictReader(f)
|
||||||
|
records = [row for row in reader if row['owner_id'] != owner_id]
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Add/update record
|
||||||
|
records.append({
|
||||||
|
'owner_id': owner_id,
|
||||||
|
'display_name': display_name,
|
||||||
|
'license_type': license_type,
|
||||||
|
'license_date': timestamp,
|
||||||
|
'current_sk': current_sk,
|
||||||
|
'voting_weight': f"{voting_weight:.2f}",
|
||||||
|
'status': status,
|
||||||
|
'last_updated': timestamp
|
||||||
|
})
|
||||||
|
|
||||||
|
# Write back
|
||||||
|
with open(book_file, 'w', newline='') as f:
|
||||||
|
fieldnames = ['owner_id', 'display_name', 'license_type', 'license_date', 'current_sk', 'voting_weight', 'status', 'last_updated']
|
||||||
|
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
||||||
|
writer.writeheader()
|
||||||
|
writer.writerows(records)
|
||||||
|
|
||||||
|
def check_sk_upgrades(self):
|
||||||
|
"""Check for automatic SK-based license upgrades"""
|
||||||
|
print("🔍 Checking for automatic license upgrades...")
|
||||||
|
|
||||||
|
# Load current SK balances from karma ledger
|
||||||
|
sk_balances = self.get_current_sk_balances()
|
||||||
|
|
||||||
|
# Check each owner for upgrade eligibility
|
||||||
|
book_file = os.path.join(self.base_path, 'ownership', 'book-of-owners.csv')
|
||||||
|
with open(book_file, 'r') as f:
|
||||||
|
reader = csv.DictReader(f)
|
||||||
|
for owner in reader:
|
||||||
|
owner_id = owner['owner_id']
|
||||||
|
current_license = owner['license_type']
|
||||||
|
display_name = owner['display_name']
|
||||||
|
current_sk = sk_balances.get(display_name, 0)
|
||||||
|
|
||||||
|
# Check campaign -> watch upgrade
|
||||||
|
if current_license == 'campaign' and current_sk >= 100:
|
||||||
|
print(f"🎉 Auto-upgrade: {display_name} (Campaign → Watch) - {current_sk} SK earned!")
|
||||||
|
self.record_license_transaction(owner_id, "UPGRADE_SK", "campaign", "watch", 0, "sk_threshold_100")
|
||||||
|
self.update_book_of_owners(owner_id, display_name, "watch", current_sk)
|
||||||
|
|
||||||
|
def get_current_sk_balances(self):
|
||||||
|
"""Get current SK balances from karma ledger"""
|
||||||
|
balances = {}
|
||||||
|
karma_file = os.path.join(self.base_path, 'ledger', 'social-karma', 'transactions.csv')
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(karma_file, 'r') as f:
|
||||||
|
reader = csv.DictReader(f)
|
||||||
|
for row in reader:
|
||||||
|
if row['type'] == 'KARMA':
|
||||||
|
balances[row['to']] = balances.get(row['to'], 0) + int(row['amount'])
|
||||||
|
elif row['type'] == 'DECAY':
|
||||||
|
balances[row['from']] = balances.get(row['from'], 0) - int(row['amount'])
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return balances
|
||||||
|
|
||||||
|
def validate_currency_award(self, username, currency_type, amount):
|
||||||
|
"""Validate if user can receive SC or SK award"""
|
||||||
|
# Get user's license type
|
||||||
|
book_file = os.path.join(self.base_path, 'ownership', 'book-of-owners.csv')
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(book_file, 'r') as f:
|
||||||
|
reader = csv.DictReader(f)
|
||||||
|
for owner in reader:
|
||||||
|
if owner['display_name'] == username:
|
||||||
|
license_type = owner['license_type']
|
||||||
|
|
||||||
|
# Check SC eligibility
|
||||||
|
if currency_type == 'SC':
|
||||||
|
can_earn = self.policies['license_capabilities'][license_type]['can_earn_sc']
|
||||||
|
if not can_earn:
|
||||||
|
return False, f"{username} has {license_type} license - cannot earn SC (needs work/organizational)"
|
||||||
|
|
||||||
|
# Check SK eligibility
|
||||||
|
elif currency_type == 'SK':
|
||||||
|
can_earn = self.policies['license_capabilities'][license_type]['can_earn_sk']
|
||||||
|
if not can_earn:
|
||||||
|
return False, f"{username} has {license_type} license - cannot earn SK"
|
||||||
|
|
||||||
|
return True, f"✅ {username} eligible for {amount} {currency_type}"
|
||||||
|
|
||||||
|
return False, f"❌ {username} not found in Book of Owners"
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
return False, "❌ Book of Owners not found"
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main owner management interface"""
|
||||||
|
manager = OwnershipManager()
|
||||||
|
|
||||||
|
print("📖 BOOK OF OWNERS MANAGEMENT")
|
||||||
|
print("=" * 40)
|
||||||
|
print("1. Add new owner")
|
||||||
|
print("2. Check SK upgrade eligibility")
|
||||||
|
print("3. Validate currency award")
|
||||||
|
print("4. Show current owners")
|
||||||
|
|
||||||
|
# For now, just show current owners
|
||||||
|
book_file = os.path.join(manager.base_path, 'ownership', 'book-of-owners.csv')
|
||||||
|
try:
|
||||||
|
with open(book_file, 'r') as f:
|
||||||
|
reader = csv.DictReader(f)
|
||||||
|
owners = list(reader)
|
||||||
|
|
||||||
|
if owners:
|
||||||
|
print(f"\n📊 Current Owners: {len([o for o in owners if o['owner_id']])}")
|
||||||
|
print("-" * 60)
|
||||||
|
for owner in owners:
|
||||||
|
if owner['owner_id']: # Skip header comments
|
||||||
|
print(f"{owner['owner_id']}: {owner['display_name']} ({owner['license_type']}) - {owner['current_sk']} SK")
|
||||||
|
else:
|
||||||
|
print("📝 No owners registered yet")
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("📝 Book of Owners not created yet")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -0,0 +1,123 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Currency Ledger Validation Script
|
||||||
|
Ensures ledger integrity and policy compliance
|
||||||
|
"""
|
||||||
|
|
||||||
|
import csv
|
||||||
|
import yaml
|
||||||
|
from datetime import datetime
|
||||||
|
import os
|
||||||
|
|
||||||
|
def load_policies():
|
||||||
|
"""Load policy configuration files"""
|
||||||
|
policies = {}
|
||||||
|
policy_dir = os.path.join(os.path.dirname(__file__), '..', 'policies')
|
||||||
|
|
||||||
|
with open(os.path.join(policy_dir, 'credit-rates.yml'), 'r') as f:
|
||||||
|
policies['credit_rates'] = yaml.safe_load(f)
|
||||||
|
|
||||||
|
with open(os.path.join(policy_dir, 'karma-rules.yml'), 'r') as f:
|
||||||
|
policies['karma_rules'] = yaml.safe_load(f)
|
||||||
|
|
||||||
|
with open(os.path.join(policy_dir, 'validation-rules.yml'), 'r') as f:
|
||||||
|
policies['validation'] = yaml.safe_load(f)
|
||||||
|
|
||||||
|
return policies
|
||||||
|
|
||||||
|
def validate_sc_ledger():
|
||||||
|
"""Validate Smartup Credits ledger"""
|
||||||
|
print("🔍 Validating Smartup Credits ledger...")
|
||||||
|
|
||||||
|
total_sc = 0
|
||||||
|
ledger_file = os.path.join(os.path.dirname(__file__), '..', 'ledger', 'smartup-credits', 'transactions.csv')
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(ledger_file, 'r') as f:
|
||||||
|
reader = csv.DictReader(f)
|
||||||
|
transaction_count = 0
|
||||||
|
|
||||||
|
for row in reader:
|
||||||
|
if row['type'] == 'SC':
|
||||||
|
total_sc += int(row['amount'])
|
||||||
|
transaction_count += 1
|
||||||
|
elif row['type'] == 'REDEEM':
|
||||||
|
total_sc -= int(row['amount'])
|
||||||
|
transaction_count += 1
|
||||||
|
|
||||||
|
print(f"✅ Total SC Outstanding: {total_sc}")
|
||||||
|
print(f"✅ Transactions Processed: {transaction_count}")
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("❌ SC ledger file not found")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error validating SC ledger: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def validate_treasury():
|
||||||
|
"""Validate treasury balance and 3x rule"""
|
||||||
|
print("🔍 Validating treasury balance...")
|
||||||
|
|
||||||
|
treasury_file = os.path.join(os.path.dirname(__file__), '..', 'ledger', 'treasury', 'balance.csv')
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(treasury_file, 'r') as f:
|
||||||
|
reader = csv.DictReader(f)
|
||||||
|
rows = list(reader)
|
||||||
|
|
||||||
|
if rows:
|
||||||
|
latest = rows[-1]
|
||||||
|
eur_balance = float(latest['total_eur_balance'])
|
||||||
|
sc_outstanding = int(latest['sc_outstanding'])
|
||||||
|
ratio = float(latest['ratio'])
|
||||||
|
|
||||||
|
print(f"✅ EUR Treasury: €{eur_balance}")
|
||||||
|
print(f"✅ SC Outstanding: {sc_outstanding} SC")
|
||||||
|
print(f"✅ Current Ratio: {ratio:.2f}")
|
||||||
|
|
||||||
|
# Check 3x rule
|
||||||
|
if sc_outstanding <= (eur_balance * 3):
|
||||||
|
print("✅ 3x Rule: COMPLIANT")
|
||||||
|
else:
|
||||||
|
print("❌ 3x Rule: VIOLATION - Too much SC outstanding!")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print("⚠️ Treasury initialized but no transactions yet")
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("❌ Treasury file not found")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error validating treasury: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main validation function"""
|
||||||
|
print("🚀 Smartup Zero Currency Ledger Validation")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
# Load policies
|
||||||
|
try:
|
||||||
|
policies = load_policies()
|
||||||
|
print("✅ Policy files loaded successfully")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error loading policies: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Validate ledgers
|
||||||
|
sc_valid = validate_sc_ledger()
|
||||||
|
treasury_valid = validate_treasury()
|
||||||
|
|
||||||
|
print("=" * 50)
|
||||||
|
if sc_valid and treasury_valid:
|
||||||
|
print("🎉 All validations PASSED - Ledger is healthy!")
|
||||||
|
else:
|
||||||
|
print("🚨 Validation FAILED - Check errors above")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue