Repair crypto protocol cohort V0.3.1 funnel

This commit is contained in:
Daniel Maddern 2026-08-16 21:56:09 +07:00
parent d35a212aff
commit 554a865927
6 changed files with 249 additions and 107 deletions

View file

@ -58,22 +58,24 @@ from research.searxng import SearxngSearchClient, WebPageFetcher
CRYPTO_TERRITORIES = [
"MACHINE_ECONOMIC_IDENTITY",
"DECENTRALIZED_AI_COMPUTE",
"VERIFIABLE_INFERENCE_NETWORKS",
"MACHINE_SERVICE_MARKETS",
"AGENT_ECONOMIC_IDENTITY",
"AUTONOMOUS_AGENT_COMMERCE",
"DECENTRALIZED_SECURITY_MARKETS",
"VERIFIABLE_AI_INFERENCE",
"PROOF_MARKETS",
"DECENTRALIZED_COMPUTE",
"DATA_PROVENANCE_NETWORKS",
"MACHINE_TO_MACHINE_SETTLEMENT",
"AUTONOMOUS_ESCROW",
"DECENTRALIZED_INSURANCE_RISK_POOLS",
"RESOURCE_RIGHTS_MARKETS",
"DECENTRALIZED_BANDWIDTH_STORAGE",
"AI_MODEL_CONTRIBUTION_NETWORKS",
"SOFTWARE_SECURITY_BONDS",
"AUTONOMOUS_AGENT_COORDINATION",
"DECENTRALIZED_ORACLE_ATTESTATION",
"CRYPTO_NATIVE_CREATOR_DATA_RIGHTS",
"PROOF_MARKETS",
"DECENTRALIZED_DATA_CONTRIBUTION",
"MODEL_CONTRIBUTION_NETWORKS",
"COMPUTE_CONTRIBUTION_NETWORKS",
"DECENTRALIZED_RESOURCE_MARKETS",
"BANDWIDTH_STORAGE_RESOURCE_MARKETS",
"DECENTRALIZED_INSURANCE_RISK_POOLS",
"PROTOCOLIZED_ESCROW",
"MACHINE_REPUTATION_WITH_ECONOMIC_STAKE",
"PROVIDER_COORDINATION_NETWORKS",
"AUTONOMOUS_INFRASTRUCTURE_MARKETS",
"OPEN_CRYPTO_CATEGORY",
]
@ -111,7 +113,11 @@ CRYPTO_SCORE_DIMENSIONS = [
"PRE_TOKEN_MONETIZATION_POTENTIAL",
]
CRYPTO_RESEARCH_CATEGORIES = ["USER_PAIN", "EXISTING_PROTOCOLS", "FAILED_PRECEDENTS", "ONCHAIN_ALTERNATIVES", "OFFCHAIN_ALTERNATIVES", "TOKEN_MODELS", "COLLATERAL_MODELS", "STAKING_SLASHING_PRECEDENTS", "PROVIDER_ECONOMICS", "NETWORK_BOOTSTRAP", "SECURITY_FAILURES", "LEGAL_REGULATORY", "PRE_TOKEN_MONETIZATION", "TOKEN_LAUNCH_PRECEDENTS"]
CRYPTO_RESEARCH_CATEGORIES = ["USER_PAIN", "EXISTING_PROTOCOLS", "FAILED_PRECEDENTS", "TOKEN_UTILITY_PRECEDENTS", "SECURITY_BOND_PRECEDENTS", "SLASHING_PRECEDENTS", "RESOURCE_MARKET_PRECEDENTS", "PROVIDER_ECONOMICS", "NETWORK_BOOTSTRAP", "VALUE_CAPTURE", "TOKENOMICS_FAILURES", "SECURITY_INCIDENTS", "ONCHAIN_ALTERNATIVES", "OFFCHAIN_ALTERNATIVES", "LEGAL_REGULATORY", "PRE_TOKEN_MONETIZATION"]
STRUCTURAL_TOKEN_ROLES = {"SECURITY_BOND", "SLASHABLE_COLLATERAL", "RESOURCE_ALLOCATION", "MACHINE_ECONOMIC_IDENTITY", "PROVIDER_ADMISSION", "DECENTRALIZED_SUPPLY_COORDINATION"}
WEAK_TOKEN_ROLES = {"DEMAND_SIDE_PAYMENT", "GOVERNANCE", "PROVIDER_REWARD", "TREASURY", "ACCESS"}
TOKEN_UTILITY_SCORE_KEYS = ["SECURITY_UTILITY", "COORDINATION_UTILITY", "COLLATERAL_UTILITY", "SLASHING_UTILITY", "RESOURCE_ALLOCATION_UTILITY", "INCENTIVE_UTILITY", "NETWORK_BOOTSTRAP_UTILITY", "VALUE_CAPTURE_UTILITY", "MACHINE_ECONOMIC_UTILITY", "GOVERNANCE_UTILITY", "PAYMENT_UTILITY", "SPECULATION_DEPENDENCE"]
PRIMARY_SOURCE_DOMAINS = ["ethereum.org", "eips.ethereum.org", "github.com", "arxiv.org", "sec.gov", "cftc.gov", "immunefi.com"]
SOURCE_REJECTION_REASONS = {"IRRELEVANT": "SOURCE_REJECT_IRRELEVANT", "WRONG_CATEGORY": "SOURCE_REJECT_WRONG_CATEGORY", "LOW_AUTHORITY": "SOURCE_REJECT_LOW_AUTHORITY", "SEARCH_NOISE": "SOURCE_REJECT_SEARCH_NOISE", "UNPARSABLE": "SOURCE_REJECT_UNPARSABLE", "DUPLICATE": "SOURCE_REJECT_DUPLICATE"}
@ -148,15 +154,15 @@ class CryptoVentureService:
objective="Generate crypto-native protocol ventures where onchain execution and a native token are genuinely necessary for real usage, not speculation.",
constraints={"venture_track": VentureTrack.CRYPTO_PROTOCOL, "no_token_sale": True, "no_fundraising": True, "no_mainnet_issuance": True, "no_us_targeted_activity": True, "testnet_or_local_only": True, "no_real_spend": True, "no_user_contact": True},
optimization_targets=["token necessity", "onchain necessity", "real usage demand", "value accrual", "sustainable tokenomics", "autonomous operability", "regulatory manageability", "security model quality"],
metadata={"milestone": "CRYPTO_PROTOCOL_VENTURE_COHORT_V0.3", "venture_track": VentureTrack.CRYPTO_PROTOCOL},
metadata={"milestone": "CRYPTO_PROTOCOL_VENTURE_COHORT_V0.3.1", "venture_track": VentureTrack.CRYPTO_PROTOCOL},
)
self._artifact(None, mandate, "CRYPTO_VENTURE_MANDATE", "Crypto Protocol Venture V0.3 Mandate", mandate.constraints, "Crypto protocol cohort mandate. Sol-native problem-first ideation. No token sale, fundraising, or mainnet issuance.", "crypto_venture")
self._artifact(None, mandate, "CRYPTO_VENTURE_MANDATE", "Crypto Protocol Venture V0.3.1 Mandate", mandate.constraints, "Crypto protocol cohort mandate. Sol-native problem-first ideation and strong native token utility search. No token sale, fundraising, or mainnet issuance.", "crypto_venture")
return mandate
def prepare_cohort(self, *, size: int, graph_run=None, concurrency: int = 2) -> VentureCohort:
mandate = self.create_crypto_mandate()
cohort_id = f"CPV03-{time.strftime('%Y%m%d%H%M%S')}-{uuid.uuid4().hex[:8]}"
return VentureCohort.objects.create(cohort_id=cohort_id, mandate=mandate, cohort_size=size, graph_run=graph_run, concurrency=concurrency, status="PREPARING_CRYPTO", graph_versions={"cohort": "crypto_venture_cohort v3"}, research_policy={"source_linked_evidence_required": True, "research_insufficient_if_no_sources": True, "primary_source_first": True, "minimum_category_evidence": "one strong source or multiple independent medium sources", "crypto_categories": CRYPTO_RESEARCH_CATEGORIES}, scoring_policy={"dimensions": CRYPTO_SCORE_DIMENSIONS, "strict_token_filter": True, "sol_problem_first_generation": True}, metadata={"milestone": "CRYPTO_PROTOCOL_VENTURE_COHORT_V0.3", "venture_track": VentureTrack.CRYPTO_PROTOCOL, "real_spend": 0, "real_customer_outreach": False, "token_sale": False, "fundraising": False, "mainnet_issuance": False, "v02_baseline": {"raw": 30, "crypto_survivors": 2, "autonomous_survivors": 0, "finalists": 0}})
cohort_id = f"CPV031-{time.strftime('%Y%m%d%H%M%S')}-{uuid.uuid4().hex[:8]}"
return VentureCohort.objects.create(cohort_id=cohort_id, mandate=mandate, cohort_size=size, graph_run=graph_run, concurrency=concurrency, status="PREPARING_CRYPTO", graph_versions={"cohort": "crypto_venture_cohort v3.1"}, research_policy={"source_linked_evidence_required": True, "research_insufficient_if_no_sources": True, "primary_source_first": True, "minimum_category_evidence": "one strong source or multiple independent medium sources", "crypto_categories": CRYPTO_RESEARCH_CATEGORIES}, scoring_policy={"dimensions": CRYPTO_SCORE_DIMENSIONS, "strict_token_filter": True, "sol_problem_first_generation": True, "strong_native_token_utility_required": True, "structural_roles": sorted(STRUCTURAL_TOKEN_ROLES)}, metadata={"milestone": "CRYPTO_PROTOCOL_VENTURE_COHORT_V0.3.1", "venture_track": VentureTrack.CRYPTO_PROTOCOL, "real_spend": 0, "real_customer_outreach": False, "token_sale": False, "fundraising": False, "mainnet_issuance": False, "v02_baseline": {"raw": 30, "crypto_survivors": 2, "autonomous_survivors": 0, "finalists": 0}, "v03_baseline": {"raw": 20, "onchain_rejected": 5, "onchain_passed": 15, "token_unnecessary": 12, "token_optional": 3, "crypto_survivors": 0, "finalists": 0}})
def generate_protocols(self, cohort: VentureCohort) -> list[CompanyProposal]:
accepted = []
@ -170,7 +176,7 @@ class CryptoVentureService:
proposal = self._create_proposal(cohort.mandate, payload, source, territory)
VentureCohortMember.objects.create(cohort=cohort, proposal=proposal, metadata={"territory": territory})
accepted.append(proposal)
cohort.metrics = {**cohort.metrics, "raw_target": cohort.cohort_size, "raw_generated": len(accepted), "raw_sol_theses": len([p for p in accepted if p.metadata.get("generation_source") == "sol"]), "requested_protocol_count": cohort.cohort_size, "generation_attempts": attempts, "accepted_protocols": len(accepted), "duplicate_rejections": 0, "token_necessity_rejections": 0, "generation_sources": sorted({p.metadata.get("generation_source", "unknown") for p in accepted}), "model_usage": dict(model_usage), "sol_generation_requests": model_usage.get("sol_generation_requests", 0), "fallback_count": model_usage.get("fallback_count", 0)}
cohort.metrics = {**cohort.metrics, "raw_theses": len(accepted), "raw_target": cohort.cohort_size, "raw_generated": len(accepted), "raw_sol_theses": len([p for p in accepted if p.metadata.get("generation_source") == "sol"]), "requested_protocol_count": cohort.cohort_size, "generation_attempts": attempts, "accepted_protocols": len(accepted), "duplicate_rejections": 0, "token_necessity_rejections": 0, "generation_sources": sorted({p.metadata.get("generation_source", "unknown") for p in accepted}), "model_usage": dict(model_usage), "sol_generation_requests": model_usage.get("sol_generation_requests", 0), "sol_onchain_judge_requests": model_usage.get("sol_onchain_judge_requests", 0), "fallback_count": model_usage.get("fallback_count", 0)}
cohort.status = "PROTOCOLS_GENERATED"
cohort.save(update_fields=["metrics", "status", "updated_at"])
return accepted
@ -185,10 +191,11 @@ class CryptoVentureService:
VentureGenerationRejection.objects.create(cohort=cohort, slot_index=member.rank or 0, attempt=1, decision=NoveltyGateDecision.REGENERATE_HARD_EXCLUSION, reason="removed by onchain necessity gate", candidate={"title": proposal.title, "onchain_necessity_score": assessment.onchain_necessity_score}, similarity_score=0.0)
member.delete()
proposal.status = CompanyProposalStatus.REJECTED
proposal.metadata = {**proposal.metadata, "routed_to_saas": True, "onchain_rejected": True}
proposal.metadata = {**proposal.metadata, "routed_to_saas": True, "routed_to_venture_studio": True, "onchain_rejected": True, "crypto_failure_reason": "onchain necessity failed"}
proposal.save(update_fields=["status", "metadata", "updated_at"])
removed += 1
cohort.metrics = {**cohort.metrics, "onchain_rejected": cohort.metrics.get("onchain_rejected", 0) + removed, "crypto_survivors_after_onchain": cohort.members.count()}
onchain_passed = cohort.members.count()
cohort.metrics = {**cohort.metrics, "onchain_rejected": cohort.metrics.get("onchain_rejected", 0) + removed, "onchain_passed": onchain_passed, "crypto_survivors_after_onchain": onchain_passed, "token_design_skipped_due_to_onchain_rejection": cohort.metrics.get("token_design_skipped_due_to_onchain_rejection", 0) + removed}
cohort.save(update_fields=["metrics", "updated_at"])
return assessments
@ -226,20 +233,56 @@ class CryptoVentureService:
def regenerate_rejected_slots(self, cohort: VentureCohort, *, reason: str = "novelty_or_token_gate") -> list[CompanyProposal]:
created: list[CompanyProposal] = []
cohort.metrics = {**cohort.metrics, "regeneration_attempts": cohort.metrics.get("regeneration_attempts", 0), "regenerated_protocols": cohort.metrics.get("regenerated_protocols", 0), "crypto_survivors": cohort.members.count(), "unfilled_slots_after_regeneration": max(0, cohort.cohort_size - cohort.members.count()), "regeneration_policy": "V0.3 uses total raw Sol generation budget; offchain or weak token ideas are not force-filled."}
cohort.metrics = {**cohort.metrics, "regeneration_attempts": cohort.metrics.get("regeneration_attempts", 0), "regenerated_protocols": cohort.metrics.get("regenerated_protocols", 0), "crypto_survivors": cohort.members.count(), "unfilled_slots_after_regeneration": max(0, cohort.cohort_size - cohort.members.count()), "regeneration_policy": "V0.3.1 uses total raw Sol generation budget; offchain or weak token ideas are not force-filled."}
cohort.save(update_fields=["metrics", "updated_at"])
return created
def token_necessity_gate(self, cohort: VentureCohort) -> list[TokenUtilityAssessment]:
assessments = [self.assess_token_necessity(member.proposal) for member in cohort.members.select_related("proposal")]
model_usage = Counter(cohort.metrics.get("model_usage", {}))
before = cohort.members.count()
assessments = []
for member in cohort.members.select_related("proposal"):
if not member.proposal.metadata.get("crypto", {}).get("token_design_completed"):
used = self.derive_token_design(member.proposal)
model_usage.update(used)
assessments.append(self.assess_token_necessity(member.proposal))
model_usage["sol_token_utility_judge_requests"] += 1 if self.final_ic_model_hint == "sol" else 0
removed = self._remove_weak_token_members(cohort)
cohort.metrics = {**cohort.metrics, **removed}
cohort.metrics = {**cohort.metrics, **removed, "token_design_attempts": cohort.metrics.get("token_design_attempts", 0) + before, "token_design_count_matches_onchain_passed": (cohort.metrics.get("token_design_attempts", 0) + before) == cohort.metrics.get("onchain_passed", before), "model_usage": dict(model_usage), "sol_token_design_requests": model_usage.get("sol_token_design_requests", 0), "sol_token_utility_judge_requests": model_usage.get("sol_token_utility_judge_requests", 0)}
cohort.save(update_fields=["metrics", "updated_at"])
return assessments
def derive_token_design(self, proposal: CompanyProposal) -> Counter:
usage = Counter()
crypto = proposal.metadata.get("crypto", {})
passes = crypto.get("generation_passes", {}) if isinstance(crypto, dict) else {}
pass_a = passes.get("pass_a_problem_network", {}) if isinstance(passes, dict) else {}
pass_b = passes.get("pass_b_onchain", {}) if isinstance(passes, dict) else {}
pass_c_prompt = "PASS C - MINIMAL DECENTRALIZED PROTOCOL ARCHITECTURE. Return JSON with protocol_architecture, participant_model, verification_model, settlement_model, resource_allocation_model, dispute_model, value_capture_model, autonomous_operating_loop. No token design yet. Thesis: " + json.dumps({"problem": pass_a or proposal.pitch, "onchain_review": pass_b}, default=str)
architecture = self._model_json(self.generation_model_hint, pass_c_prompt, purpose=ModelCapability.REASONING)
pass_d_prompt = "PASS D - NATIVE TOKEN UTILITY DESIGN. Derive the minimum native token utility only if it performs strong structural economic or security functions. Explore SECURITY_BOND, SLASHABLE_COLLATERAL, PROVIDER_ADMISSION, RESOURCE_ALLOCATION, MACHINE_ECONOMIC_IDENTITY, CONTRIBUTION_ACCOUNTING, SECURITY_BUDGET, PROTOCOL_FEE_ASSET, PROVIDER_REWARD, DEMAND_SIDE_PAYMENT, GOVERNANCE, ACCESS, TREASURY, OTHER. Payment/governance/rewards/access alone are insufficient. Return JSON with token_thesis, token_utility list, token_demand_loop list, value_capture, token_roles object where each role is REQUIRED/STRONGLY_USEFUL/USEFUL/OPTIONAL/UNNECESSARY, mechanism_fingerprint object, security_model, regulatory_risks. Architecture: " + json.dumps(architecture or pass_a or proposal.pitch, default=str)
token_design = self._model_json(self.generation_model_hint, pass_d_prompt, purpose=ModelCapability.REASONING)
usage["sol_protocol_architecture_requests" if self.generation_model_hint == "sol" else "qwen_requests"] += 1
usage["sol_token_design_requests" if self.generation_model_hint == "sol" else "qwen_requests"] += 1
if token_design:
crypto = {**crypto, "generation_passes": {**passes, "pass_c_protocol_architecture": architecture, "pass_d_token_utility": token_design}, "token_design_completed": True, "token_roles": token_design.get("token_roles", {}), "mechanism_fingerprint": token_design.get("mechanism_fingerprint", {})}
proposal.metadata = {**proposal.metadata, "crypto": crypto}
proposal.pitch = {**proposal.pitch, "Token thesis": str(token_design.get("token_thesis", proposal.pitch.get("Token thesis", ""))), "Token demand loop": self._as_list(token_design.get("token_demand_loop") or proposal.pitch.get("Token demand loop", []))}
proposal.save(update_fields=["metadata", "pitch", "updated_at"])
if hasattr(proposal, "protocol_thesis"):
proposal.protocol_thesis.token_thesis = str(token_design.get("token_thesis", proposal.protocol_thesis.token_thesis))
proposal.protocol_thesis.utility_categories = self._as_list(token_design.get("token_utility") or proposal.protocol_thesis.utility_categories)
proposal.protocol_thesis.save(update_fields=["token_thesis", "utility_categories", "updated_at"])
if hasattr(proposal, "token_demand_loop"):
proposal.token_demand_loop.loop = self._as_list(token_design.get("token_demand_loop") or proposal.token_demand_loop.loop)
proposal.token_demand_loop.save(update_fields=["loop", "updated_at"])
return usage
def _remove_weak_token_members(self, cohort: VentureCohort) -> dict[str, int]:
unnecessary = 0
optional = 0
essential = 0
strongly = 0
for member in list(cohort.members.select_related("proposal")):
proposal = member.proposal
assessment = getattr(proposal, "token_utility_assessment", None) or self.assess_token_necessity(proposal)
@ -251,9 +294,13 @@ class CryptoVentureService:
VentureGenerationRejection.objects.create(cohort=cohort, slot_index=member.rank or 0, attempt=1, decision=NoveltyGateDecision.REGENERATE_HARD_EXCLUSION, reason=f"removed by token necessity gate: {assessment.classification}", candidate={"title": proposal.title, "classification": assessment.classification}, similarity_score=0.0)
member.delete()
proposal.status = CompanyProposalStatus.REJECTED
proposal.metadata = {**proposal.metadata, "routed_to_saas": assessment.classification == TokenNecessityClassification.TOKEN_OPTIONAL}
proposal.metadata = {**proposal.metadata, "routed_to_saas": assessment.classification == TokenNecessityClassification.TOKEN_OPTIONAL, "routed_to_venture_studio": True, "crypto_failure_reason": f"token classification {assessment.classification}"}
proposal.save(update_fields=["status", "metadata", "updated_at"])
return {"token_unnecessary_rejections": cohort.metrics.get("token_unnecessary_rejections", 0) + unnecessary, "token_optional_route_to_saas": cohort.metrics.get("token_optional_route_to_saas", 0) + optional, "crypto_survivors": cohort.members.count()}
elif assessment.classification == TokenNecessityClassification.TOKEN_ESSENTIAL:
essential += 1
else:
strongly += 1
return {"token_unnecessary_rejections": cohort.metrics.get("token_unnecessary_rejections", 0) + unnecessary, "token_optional_route_to_saas": cohort.metrics.get("token_optional_route_to_saas", 0) + optional, "token_essential": cohort.metrics.get("token_essential", 0) + essential, "token_strongly_justified": cohort.metrics.get("token_strongly_justified", 0) + strongly, "serious_crypto_survivors": cohort.members.count(), "crypto_survivors": cohort.members.count()}
def light_market_research(self, cohort: VentureCohort) -> None:
started = time.monotonic()
@ -442,9 +489,13 @@ class CryptoVentureService:
return "UNAVAILABLE"
def token_red_team(self, cohort: VentureCohort) -> list[CryptoRedTeamAssessment]:
assessments = [self.red_team_proposal(member.proposal) for member in cohort.members.select_related("proposal")]
assessments = []
for member in cohort.members.select_related("proposal"):
token = getattr(member.proposal, "token_utility_assessment", None)
if token and token.classification in {TokenNecessityClassification.TOKEN_ESSENTIAL, TokenNecessityClassification.TOKEN_STRONGLY_JUSTIFIED}:
assessments.append(self.red_team_proposal(member.proposal))
counts = Counter(flag for item in assessments for flag in item.flags)
cohort.metrics = {**cohort.metrics, "token_red_team_failures": dict(counts)}
cohort.metrics = {**cohort.metrics, "token_red_team_failures": dict(counts), "token_red_team_count": len(assessments), "sol_token_red_team_requests": len(assessments) if self.final_ic_model_hint == "sol" else 0}
cohort.save(update_fields=["metrics", "updated_at"])
return assessments
@ -492,10 +543,10 @@ class CryptoVentureService:
row["rank"] = rank
review, _ = PortfolioICReview.objects.update_or_create(cohort=cohort, defaults={"rankings": rows, "top_3": top_3, "concentration": self._crypto_concentration(rows), "metadata": {"finalist_shortfall": max(0, 3 - len(top_3)), "no_fund_decision_v01": True}})
model_usage = Counter(cohort.metrics.get("model_usage", {}))
model_usage["sol_judge_requests"] += len([row for row in rows if row.get("token_necessity_classification")])
model_usage["sol_token_utility_judge_requests"] = max(model_usage.get("sol_token_utility_judge_requests", 0), cohort.metrics.get("sol_token_utility_judge_requests", 0))
model_usage["sol_final_ic_requests"] += len(rows) if self.final_ic_model_hint == "sol" else 0
model_usage["qwen_requests"] += 0
cohort.metrics = {**cohort.metrics, "crypto_ranked_count": len(rows), "crypto_top_3_count": len(top_3), "autonomous_crypto_survivors": len([row for row in rows if row.get("crypto_autonomy_class") == CryptoAutonomyClass.AUTONOMOUS_CRYPTO]), "finalists": len(top_3), "model_usage": dict(model_usage), "sol_judge_requests": model_usage.get("sol_judge_requests", 0), "sol_final_ic_requests": model_usage.get("sol_final_ic_requests", 0), "qwen_requests": model_usage.get("qwen_requests", 0)}
cohort.metrics = {**cohort.metrics, "crypto_ranked_count": len(rows), "crypto_top_3_count": len(top_3), "autonomous_crypto_survivors": len([row for row in rows if row.get("crypto_autonomy_class") == CryptoAutonomyClass.AUTONOMOUS_CRYPTO]), "assisted_high_potential": len([row for row in rows if row.get("crypto_ic_decision") == CryptoICDecisionType.ASSISTED_CRYPTO_HIGH_POTENTIAL]), "finalists": len(top_3), "model_usage": dict(model_usage), "sol_token_utility_judge_requests": model_usage.get("sol_token_utility_judge_requests", 0), "sol_final_ic_requests": model_usage.get("sol_final_ic_requests", 0), "qwen_requests": model_usage.get("qwen_requests", 0)}
cohort.status = "CRYPTO_IC_COMPLETE"
cohort.save(update_fields=["metrics", "status", "updated_at"])
return review
@ -586,9 +637,10 @@ class CryptoVentureService:
rows = review.rankings
research_health = self._research_health(rows)
routed_to_saas = [{"company": proposal.title, "token_classification": getattr(proposal, "token_utility_assessment", None).classification if hasattr(proposal, "token_utility_assessment") else None, "product_thesis": proposal.description, "reason": "Failed onchain/token counterfactual but may be valuable as pre-token/SaaS product."} for proposal in cohort.mandate.company_proposals.filter(status=CompanyProposalStatus.REJECTED, metadata__routed_to_saas=True).order_by("created_at")[:10]]
comparison = {"v02": cohort.metadata.get("v02_baseline", {"raw": 30, "crypto_survivors": 2, "autonomous_survivors": 0, "finalists": 0}), "v03": {"raw": cohort.metrics.get("raw_generated", 0), "crypto_survivors": cohort.members.count(), "autonomous_survivors": cohort.metrics.get("autonomous_crypto_survivors", 0), "finalists": len(review.top_3), "average_research_quality": research_health.get("average_coverage", 0), "idea_diversity": review.concentration}}
content = {"title": "CRYPTO VENTURE COHORT V0.3", "cohort_id": cohort.cohort_id, "graph_run": str(cohort.graph_run_id or ""), "runtime": cohort.metrics, "raw_protocols_generated": cohort.metrics.get("raw_generated", 0), "raw_sol_theses": cohort.metrics.get("raw_sol_theses", 0), "onchain_rejected": cohort.metrics.get("onchain_rejected", 0), "token_unnecessary": cohort.metrics.get("token_unnecessary_rejections", 0), "token_optional_routed_saas": cohort.metrics.get("token_optional_route_to_saas", 0), "duplicates": cohort.metrics.get("duplicate_rejections", 0), "crypto_survivors": cohort.members.count(), "autonomous_crypto_survivors": cohort.metrics.get("autonomous_crypto_survivors", 0), "security_blocked": cohort.metrics.get("protocol_security_gate_blocked", 0), "finalists": len(review.top_3), "generation_attempts": cohort.metrics.get("generation_attempts", 0), "model_usage": cohort.metrics.get("model_usage", {}), "ranking": rows, "top_3": review.top_3, "routed_to_saas": routed_to_saas, "v02_comparison": comparison, "token_red_team_failures": cohort.metrics.get("token_red_team_failures", {}), "token_utility_distribution": dict(Counter(util for row in rows for util in row.get("token_utility", []))), "crypto_thesis_saturation": review.concentration, "capability_gaps": review.capability_demand, "research_health": research_health, "system_metrics": cohort.metrics, "stop_conditions": {"token_sale": False, "nft_sale": False, "founding_membership_sale": False, "fundraising": False, "mainnet_issuance": False, "user_contact": False, "real_spend": 0}}
artifact = self._artifact(None, cohort.mandate, "CRYPTO_VENTURE_COHORT_REPORT", "Crypto Venture Cohort V0.3 Report", content, self._readable_report(content), "crypto_portfolio_ic", graph_run=cohort.graph_run)
comparison = {"v02": cohort.metadata.get("v02_baseline", {"raw": 30, "crypto_survivors": 2, "autonomous_survivors": 0, "finalists": 0}), "v03": cohort.metadata.get("v03_baseline", {}), "v031": {"raw": cohort.metrics.get("raw_generated", 0), "onchain_passed": cohort.metrics.get("onchain_passed", 0), "onchain_rejected": cohort.metrics.get("onchain_rejected", 0), "token_strongly_justified": cohort.metrics.get("token_strongly_justified", 0), "token_essential": cohort.metrics.get("token_essential", 0), "crypto_survivors": cohort.members.count(), "autonomous_survivors": cohort.metrics.get("autonomous_crypto_survivors", 0), "assisted_high_potential": cohort.metrics.get("assisted_high_potential", 0), "finalists": len(review.top_3), "average_research_quality": research_health.get("average_coverage", 0), "idea_diversity": review.concentration}}
security_summary = {"guard_reviews": cohort.metrics.get("protocol_security_gate_passed", 0) + cohort.metrics.get("protocol_security_gate_blocked", 0), "pass": cohort.metrics.get("protocol_security_gate_passed", 0), "revise_or_pass": cohort.metrics.get("protocol_security_gate_passed", 0), "block": cohort.metrics.get("protocol_security_gate_blocked", 0)}
content = {"title": "CRYPTO VENTURE COHORT V0.3.1", "cohort_id": cohort.cohort_id, "graph_run": str(cohort.graph_run_id or ""), "runtime": cohort.metrics, "raw_protocols_generated": cohort.metrics.get("raw_generated", 0), "raw_sol_theses": cohort.metrics.get("raw_sol_theses", 0), "onchain_rejected": cohort.metrics.get("onchain_rejected", 0), "onchain_passed": cohort.metrics.get("onchain_passed", 0), "token_design_attempts": cohort.metrics.get("token_design_attempts", 0), "token_design_skipped": cohort.metrics.get("token_design_skipped_due_to_onchain_rejection", 0), "token_unnecessary": cohort.metrics.get("token_unnecessary_rejections", 0), "token_optional_routed_saas": cohort.metrics.get("token_optional_route_to_saas", 0), "token_strongly_justified": cohort.metrics.get("token_strongly_justified", 0), "token_essential": cohort.metrics.get("token_essential", 0), "duplicates": cohort.metrics.get("duplicate_rejections", 0), "crypto_survivors": cohort.members.count(), "autonomous_crypto_survivors": cohort.metrics.get("autonomous_crypto_survivors", 0), "assisted_high_potential": cohort.metrics.get("assisted_high_potential", 0), "security_blocked": cohort.metrics.get("protocol_security_gate_blocked", 0), "finalists": len(review.top_3), "generation_attempts": cohort.metrics.get("generation_attempts", 0), "model_usage": cohort.metrics.get("model_usage", {}), "research_summary": research_health, "security_summary": security_summary, "ranking": rows, "top_3": review.top_3, "routed_to_saas": routed_to_saas, "v02_v03_v031_comparison": comparison, "v02_comparison": comparison, "token_red_team_failures": cohort.metrics.get("token_red_team_failures", {}), "token_utility_distribution": dict(Counter(util for row in rows for util in row.get("token_utility", []))), "crypto_thesis_saturation": review.concentration, "capability_gaps": review.capability_demand, "research_health": research_health, "system_metrics": cohort.metrics, "stop_conditions": {"token_sale": False, "nft_sale": False, "founding_membership_sale": False, "fundraising": False, "mainnet_issuance": False, "user_contact": False, "real_spend": 0}}
artifact = self._artifact(None, cohort.mandate, "CRYPTO_VENTURE_COHORT_REPORT", "Crypto Venture Cohort V0.3.1 Report", content, self._readable_report(content), "crypto_portfolio_ic", graph_run=cohort.graph_run)
cohort.status = "COMPLETE"
cohort.save(update_fields=["status", "updated_at"])
return artifact
@ -613,24 +665,28 @@ class CryptoVentureService:
def assess_token_necessity(self, proposal: CompanyProposal) -> TokenUtilityAssessment:
crypto = proposal.metadata.get("crypto", {})
text = self._proposal_text(proposal)
utilities = [u for u in crypto.get("token_utility", []) if isinstance(u, str)] or self._infer_utilities(text)
utilities = [u for u in crypto.get("token_utility", []) if isinstance(u, str)] or self._as_list(getattr(proposal, "protocol_thesis", None).utility_categories if hasattr(proposal, "protocol_thesis") else []) or self._infer_utilities(text)
roles = self.token_role_decomposition(proposal)
utility_profile = self.token_utility_profile(proposal, roles)
strong_count = sum(1 for utility in utilities if utility.lower() in ALLOWED_TOKEN_UTILITIES or any(term in utility.lower() for term in ["stake", "slash", "collateral", "fee", "marketplace", "attestation", "compute", "machine", "security"]))
required_roles = len(roles.required_roles)
strong_roles = [role for role, value in roles.roles.items() if value in {"REQUIRED", "STRONGLY_USEFUL"}]
structural_roles = [role for role in strong_roles if role in STRUCTURAL_TOKEN_ROLES]
required_roles = len(strong_roles)
weak = any(term in text for term in ["meme", "speculative", "community token", "marketing token", "community marketing", "governance token only", "token gated subscription"])
payment_only = roles.required_roles == ["PAYMENT"]
score = min(100, 25 + strong_count * 10 + required_roles * 16 + (12 if "slash" in text or "slashing" in text else 0) + (8 if "provider" in text else 0) - (25 if payment_only else 0) - (35 if weak else 0))
weak_only = bool(strong_roles) and not structural_roles and all(role in WEAK_TOKEN_ROLES for role in strong_roles)
payment_only = strong_roles == ["DEMAND_SIDE_PAYMENT"] or roles.roles.get("PROTOCOL_FEE_ASSET") in {"REQUIRED", "STRONGLY_USEFUL"} and len(strong_roles) <= 1
score = min(100, 35 + strong_count * 4 + len(strong_roles) * 8 + len(structural_roles) * 13 + (12 if "slash" in text or "slashing" in text else 0) + (8 if "provider" in text else 0) - (35 if payment_only or weak_only else 0) - (35 if weak else 0) - int(utility_profile.get("SPECULATION_DEPENDENCE", 0) * 0.25))
economic_model = getattr(proposal, "token_economic_model", None)
model_payload = {"unit_of_service": economic_model.unit_of_service, "payment_asset": economic_model.payment_asset, "stake_requirement": economic_model.stake_requirement, "collateral_requirement": economic_model.collateral_requirement} if economic_model else {}
sol_review = self._sol_json("CRYPTO_TOKEN_COUNTERFACTUAL_JUDGE V0.3. Independent from generation. Compare MODEL A native token, MODEL B stablecoin payments + native bond token, MODEL C stablecoin payments + ETH/stablecoin collateral, MODEL D onchain system with no proprietary token, MODEL E centralized SaaS/database. Return JSON with classification TOKEN_ESSENTIAL, TOKEN_STRONGLY_JUSTIFIED, TOKEN_OPTIONAL, or TOKEN_UNNECESSARY; score 0-100; rationale; fiat_or_database_substitution; model_a_native_token; model_b_stablecoin_payment_native_bond; model_c_external_collateral; model_d_no_proprietary_token; model_e_centralized_saas; minimum_required_crypto_architecture; minimum_required_token_architecture; native_token_removed_breaks list; native_token_removed_degradation NONE/MINOR/MODERATE/MATERIAL/CRITICAL; native_token_removed_explanation. Product/protocol/token/economic model: " + json.dumps({"pitch": proposal.pitch, "crypto": crypto, "economic_model": model_payload}, default=str))
sol_review = self._sol_json("CRYPTO_TOKEN_UTILITY_JUDGE V0.3.1. Independent from ideation, onchain review, and token design. Challenge the token; do not merely summarize it. A native token need not be mathematically impossible to substitute, but benefits must outweigh costs. Evaluate security quality, attack economics, slashing effectiveness, provider skin-in-the-game, capital efficiency, protocol-specific risk pricing, permissionless supply formation, participant coordination, resource allocation, reputation portability, value capture, network effects, bootstrapping economics, governance, and composability versus USDC/ETH/external collateral/non-transferable attestations. Return JSON with token_classification TOKEN_ESSENTIAL/TOKEN_STRONGLY_JUSTIFIED/TOKEN_OPTIONAL/TOKEN_UNNECESSARY; score 0-100; utility_scores object; strong_structural_roles list; weak_roles list; counterfactual_analysis; material_improvements_over_USDC_ETH list; native_asset_costs_and_risks list; argument_for_native_token; argument_against_native_token; final_rationale; native_token_removed_breaks list; native_token_removed_degradation NONE/MINOR/MODERATE/MATERIAL/CRITICAL; native_token_removed_explanation. Product/protocol/token/economic model: " + json.dumps({"pitch": proposal.pitch, "crypto": crypto, "roles": roles.roles, "utility_profile": utility_profile, "economic_model": model_payload}, default=str))
if sol_review:
score = float(sol_review.get("score", score))
sol_classification = str(sol_review.get("classification", ""))
sol_classification = str(sol_review.get("token_classification") or sol_review.get("classification", ""))
else:
sol_classification = ""
if score >= 82:
if len(strong_roles) >= 2 and structural_roles and score >= 85:
classification = TokenNecessityClassification.TOKEN_ESSENTIAL
elif score >= 70:
elif len(strong_roles) >= 2 and structural_roles and score >= 75:
classification = TokenNecessityClassification.TOKEN_STRONGLY_JUSTIFIED
elif score >= 50:
classification = TokenNecessityClassification.TOKEN_OPTIONAL
@ -638,43 +694,75 @@ class CryptoVentureService:
classification = TokenNecessityClassification.TOKEN_UNNECESSARY
if sol_classification in TokenNecessityClassification.values:
classification = sol_classification
degradation = str((sol_review or {}).get("native_token_removed_degradation", "MATERIAL" if required_roles else "MINOR"))
if degradation in {"NONE", "MINOR"} and classification in {TokenNecessityClassification.TOKEN_ESSENTIAL, TokenNecessityClassification.TOKEN_STRONGLY_JUSTIFIED}:
degradation = str((sol_review or {}).get("native_token_removed_degradation", "MATERIAL" if structural_roles else "MINOR"))
if weak:
classification = TokenNecessityClassification.TOKEN_UNNECESSARY
score = min(score, 35)
elif payment_only or weak_only or not structural_roles:
classification = TokenNecessityClassification.TOKEN_OPTIONAL if score >= 45 else TokenNecessityClassification.TOKEN_UNNECESSARY
score = min(score, 62)
if (len(strong_roles) < 2 or not structural_roles or degradation in {"NONE", "MINOR"}) and classification in {TokenNecessityClassification.TOKEN_ESSENTIAL, TokenNecessityClassification.TOKEN_STRONGLY_JUSTIFIED}:
classification = TokenNecessityClassification.TOKEN_OPTIONAL
score = min(score, 62)
proposal.metadata = {**proposal.metadata, "crypto": {**crypto, "counterfactual_judge_model": self.final_ic_model_hint, "counterfactual_judge_used": bool(sol_review)}}
proposal.metadata = {**proposal.metadata, "crypto": {**crypto, "token_utility_judge_model": self.final_ic_model_hint, "token_utility_judge_used": bool(sol_review), "token_utility_profile": utility_profile, "strong_structural_roles": structural_roles, "strong_token_roles": strong_roles}}
proposal.save(update_fields=["metadata", "updated_at"])
return TokenUtilityAssessment.objects.update_or_create(proposal=proposal, defaults={"classification": classification, "token_necessity_score": score, "utility_categories": utilities, "fiat_or_database_substitution": str((sol_review or {}).get("fiat_or_database_substitution", "If normal fiat/stablecoin/database credits preserve the core coordination, route to SaaS.")), "rationale": str((sol_review or {}).get("rationale", "Token score derives from genuinely required roles, not native payment currency alone.")), "metadata": {"weak_utility_terms": INSUFFICIENT_TOKEN_UTILITIES, "sol_counterfactual_review": sol_review or {}, "independent_counterfactual_judge": "CRYPTO_TOKEN_COUNTERFACTUAL_JUDGE", "required_roles": roles.required_roles, "payment_only_penalty": payment_only, "model_a_native_token": (sol_review or {}).get("model_a_native_token", {}), "model_b_stablecoin_payment_native_bond": (sol_review or {}).get("model_b_stablecoin_payment_native_bond", {}), "model_c_external_collateral": (sol_review or {}).get("model_c_external_collateral", {}), "model_d_no_proprietary_token": (sol_review or {}).get("model_d_no_proprietary_token", {}), "model_e_centralized_saas": (sol_review or {}).get("model_e_centralized_saas", {}), "minimum_required_crypto_architecture": (sol_review or {}).get("minimum_required_crypto_architecture", ""), "minimum_required_token_architecture": (sol_review or {}).get("minimum_required_token_architecture", ""), "native_token_removed_breaks": self._as_list((sol_review or {}).get("native_token_removed_breaks")), "native_token_removed_degradation": degradation, "native_token_removed_explanation": (sol_review or {}).get("native_token_removed_explanation", "")}})[0]
return TokenUtilityAssessment.objects.update_or_create(proposal=proposal, defaults={"classification": classification, "token_necessity_score": score, "utility_categories": utilities, "fiat_or_database_substitution": str((sol_review or {}).get("counterfactual_analysis", "USDC/ETH/external collateral may preserve basic operation but must be compared against protocol-specific security and coordination improvements.")), "rationale": str((sol_review or {}).get("final_rationale") or (sol_review or {}).get("rationale") or "Token score derives from structural utility, not native payment currency alone."), "metadata": {"weak_utility_terms": INSUFFICIENT_TOKEN_UTILITIES, "sol_counterfactual_review": sol_review or {}, "sol_token_utility_judge": sol_review or {}, "independent_token_utility_judge": "CRYPTO_TOKEN_UTILITY_JUDGE", "argument_for_native_token": (sol_review or {}).get("argument_for_native_token", ""), "argument_against_native_token": (sol_review or {}).get("argument_against_native_token", ""), "utility_scores": (sol_review or {}).get("utility_scores", utility_profile), "strong_structural_roles": structural_roles, "strong_token_roles": strong_roles, "weak_roles": (sol_review or {}).get("weak_roles", []), "material_improvements_over_USDC_ETH": self._as_list((sol_review or {}).get("material_improvements_over_USDC_ETH")), "native_asset_costs_and_risks": self._as_list((sol_review or {}).get("native_asset_costs_and_risks")), "required_roles": roles.required_roles, "payment_only_penalty": payment_only, "native_token_removed_breaks": self._as_list((sol_review or {}).get("native_token_removed_breaks")), "native_token_removed_degradation": degradation, "native_token_removed_explanation": (sol_review or {}).get("native_token_removed_explanation", "")}})[0]
def token_role_decomposition(self, proposal: CompanyProposal) -> TokenRoleDecomposition:
text = self._proposal_text(proposal)
explicit_roles = proposal.metadata.get("crypto", {}).get("token_roles", {}) if isinstance(proposal.metadata, dict) else {}
roles = {}
role_terms = {
"PAYMENT": ["fee", "payment", "settlement"],
"SECURITY_BOND": ["bond", "security budget"],
"SLASHABLE_COLLATERAL": ["slash", "slashing", "collateral"],
"PROVIDER_ADMISSION": ["provider admission", "permissionless provider", "admission"],
"RESOURCE_ALLOCATION": ["resource allocation", "scarce", "quota", "bandwidth", "storage", "compute slot"],
"MACHINE_ECONOMIC_IDENTITY": ["machine economic", "machine identity", "agent identity", "reputation"],
"CONTRIBUTION_ACCOUNTING": ["contribution", "contributor", "accounting"],
"SECURITY_BUDGET": ["security budget"],
"PROTOCOL_FEE_ASSET": ["protocol fee", "fee asset"],
"PROVIDER_REWARD": ["provider reward", "reward"],
"DEMAND_SIDE_PAYMENT": ["payment", "settlement"],
"GOVERNANCE": ["governance", "vote"],
"RESOURCE_ACCESS": ["access", "scarce", "quota"],
"REPUTATION": ["reputation", "attestation"],
"REWARD": ["reward", "provider reward"],
"ACCESS": ["access"],
"TREASURY": ["treasury"],
"OTHER": [],
}
for role, terms in role_terms.items():
if role == "PAYMENT" and any(term in text for term in terms):
value = TokenRoleRequirement.USEFUL
explicit = str(explicit_roles.get(role, "")).upper() if isinstance(explicit_roles, dict) else ""
if explicit in {"REQUIRED", "STRONGLY_USEFUL", "USEFUL", "OPTIONAL", "UNNECESSARY"}:
value = explicit
elif explicit_roles:
value = TokenRoleRequirement.UNNECESSARY
elif role == "GOVERNANCE" and any(term in text for term in terms) and not any(term in text for term in ["parameter", "slashing", "treasury"]):
value = TokenRoleRequirement.OPTIONAL
elif any(term in text for term in terms):
value = TokenRoleRequirement.REQUIRED if role in {"SECURITY_BOND", "SLASHABLE_COLLATERAL", "REPUTATION"} else TokenRoleRequirement.USEFUL
value = "REQUIRED" if role in STRUCTURAL_TOKEN_ROLES else "USEFUL"
else:
value = TokenRoleRequirement.UNNECESSARY
roles[role] = value
required = [role for role, value in roles.items() if value == TokenRoleRequirement.REQUIRED]
stablecoin = {"MODEL_A_native_payment_staking_governance": "baseline proposal", "MODEL_B_stablecoin_payment_native_bond": "preferred if payment utility is separable", "MODEL_C_stablecoin_payment_stablecoin_collateral": "valid if slashing/collateral does not need protocol-native exposure", "MODEL_D_onchain_no_proprietary_token": "valid if proprietary token adds no security/resource allocation advantage", "MODEL_E_centralized_saas_database": "routes to SaaS if verification/settlement/reputation do not degrade", "usdc_identical_payment_utility": roles.get("PAYMENT") != TokenRoleRequirement.REQUIRED, "external_collateral_identical_security": "SLASHABLE_COLLATERAL" not in required and "SECURITY_BOND" not in required, "stable_collateral_identical_security": "SLASHABLE_COLLATERAL" not in required and "SECURITY_BOND" not in required}
required = [role for role, value in roles.items() if value in {"REQUIRED", "STRONGLY_USEFUL"}]
stablecoin = {"MODEL_A_native_payment_staking_governance": "baseline proposal", "MODEL_B_stablecoin_payment_native_bond": "preferred if payment utility is separable", "MODEL_C_stablecoin_payment_stablecoin_collateral": "valid if slashing/collateral does not need protocol-native exposure", "MODEL_D_onchain_no_proprietary_token": "valid if proprietary token adds no security/resource allocation advantage", "MODEL_E_centralized_saas_database": "routes to SaaS if verification/settlement/reputation do not degrade", "usdc_identical_payment_utility": roles.get("DEMAND_SIDE_PAYMENT") not in {"REQUIRED", "STRONGLY_USEFUL"}, "external_collateral_identical_security": "SLASHABLE_COLLATERAL" not in required and "SECURITY_BOND" not in required, "stable_collateral_identical_security": "SLASHABLE_COLLATERAL" not in required and "SECURITY_BOND" not in required}
outcome = "Native token removal materially degrades security/reputation if required roles remain." if required else "Native token removed changes little; route to SaaS or revise token model."
return TokenRoleDecomposition.objects.update_or_create(proposal=proposal, defaults={"roles": roles, "required_roles": required, "stablecoin_counterfactual": stablecoin, "native_token_removed_outcome": outcome})[0]
def token_utility_profile(self, proposal: CompanyProposal, roles: TokenRoleDecomposition) -> dict[str, int]:
text = self._proposal_text(proposal)
score = {key: 0 for key in TOKEN_UTILITY_SCORE_KEYS}
score["SECURITY_UTILITY"] = 85 if roles.roles.get("SECURITY_BOND") in {"REQUIRED", "STRONGLY_USEFUL"} else 35
score["COLLATERAL_UTILITY"] = 85 if roles.roles.get("SLASHABLE_COLLATERAL") in {"REQUIRED", "STRONGLY_USEFUL"} else 30
score["SLASHING_UTILITY"] = 82 if "slash" in text and roles.roles.get("SLASHABLE_COLLATERAL") in {"REQUIRED", "STRONGLY_USEFUL"} else 25
score["RESOURCE_ALLOCATION_UTILITY"] = 82 if roles.roles.get("RESOURCE_ALLOCATION") in {"REQUIRED", "STRONGLY_USEFUL"} else 25
score["MACHINE_ECONOMIC_UTILITY"] = 84 if roles.roles.get("MACHINE_ECONOMIC_IDENTITY") in {"REQUIRED", "STRONGLY_USEFUL"} else 25
score["COORDINATION_UTILITY"] = 75 if any(roles.roles.get(role) in {"REQUIRED", "STRONGLY_USEFUL"} for role in ["PROVIDER_ADMISSION", "CONTRIBUTION_ACCOUNTING", "RESOURCE_ALLOCATION"]) else 35
score["INCENTIVE_UTILITY"] = 70 if roles.roles.get("PROVIDER_REWARD") in {"REQUIRED", "STRONGLY_USEFUL", "USEFUL"} else 25
score["NETWORK_BOOTSTRAP_UTILITY"] = 75 if "bootstrap" in text or roles.roles.get("PROVIDER_ADMISSION") in {"REQUIRED", "STRONGLY_USEFUL"} else 30
score["VALUE_CAPTURE_UTILITY"] = 75 if "value" in text or roles.roles.get("PROTOCOL_FEE_ASSET") in {"REQUIRED", "STRONGLY_USEFUL", "USEFUL"} else 30
score["GOVERNANCE_UTILITY"] = 45 if roles.roles.get("GOVERNANCE") in {"REQUIRED", "STRONGLY_USEFUL", "USEFUL"} else 10
score["PAYMENT_UTILITY"] = 45 if roles.roles.get("DEMAND_SIDE_PAYMENT") in {"REQUIRED", "STRONGLY_USEFUL", "USEFUL"} else 10
score["SPECULATION_DEPENDENCE"] = 85 if any(term in text for term in ["price appreciation", "buyback", "yield", "apy", "speculat"]) else 15
return score
def assess_pretoken_monetization(self, proposal: CompanyProposal) -> PreTokenMonetizationAssessment:
text = self._proposal_text(proposal)
mode = PreTokenMonetizationMode.STABLECOIN_USAGE_FEES if "usage" in text or "api" in text else PreTokenMonetizationMode.PAID_BETA_ACCESS if "testnet" in text else PreTokenMonetizationMode.NONE
@ -711,6 +799,9 @@ class CryptoVentureService:
if payload.get("generation_passes"):
proposal.metadata = {**proposal.metadata, "crypto": {**proposal.metadata["crypto"], "generation_passes": payload.get("generation_passes", {}), "problem_first_pass_a_had_no_token": True, "pre_token_product": payload.get("pre_token_product"), "pre_token_customer": payload.get("pre_token_customer"), "pre_token_value": payload.get("pre_token_value"), "pre_token_payment_method": payload.get("pre_token_payment_method"), "pre_token_revenue_model": payload.get("pre_token_revenue_model")}}
proposal.save(update_fields=["metadata", "updated_at"])
if payload.get("token_roles"):
proposal.metadata = {**proposal.metadata, "crypto": {**proposal.metadata["crypto"], "token_roles": payload.get("token_roles", {})}}
proposal.save(update_fields=["metadata", "updated_at"])
ProtocolThesis.objects.create(proposal=proposal, product_thesis=product, protocol_thesis=protocol, token_thesis=token, network_effect=proposal.metadata["crypto"]["network_effect"], bootstrap_plan=proposal.metadata["crypto"]["bootstrap_plan"], autonomous_operability="Artifex can build/testnet deploy/monitor only; mainnet and issuance stop at human legal gate.", utility_categories=proposal.metadata["crypto"]["token_utility"], protocol_category=territory)
TokenDemandLoop.objects.create(proposal=proposal, loop=demand_loop, real_usage_driver=str(payload.get("real_usage_driver") or product), non_speculative_demand=not any(term in " ".join(demand_loop).lower() for term in ["speculation", "price go up"]), bootstrap_without_token=proposal.metadata["crypto"]["bootstrap_plan"])
self.bus.publish("CRYPTO_PROTOCOL_PROPOSED", payload={"proposal_id": str(proposal.id), "territory": territory, "source": source})
@ -727,10 +818,7 @@ class CryptoVentureService:
pass_b_prompt = "PASS B - ONCHAIN NECESSITY. Independently evaluate whether this coordination system materially improves when implemented onchain. Return JSON with onchain_necessity_score 0-100, why_onchain, offchain_substitute, pass_onchain boolean, reasons list. Consider trust minimization, neutral settlement, permissionless participation, verifiable state, escrow, programmable guarantees, censorship resistance, cross-organization coordination, and machine-to-machine interaction. Thesis: " + json.dumps(pass_a, default=str)
pass_b = self._model_json(self.generation_model_hint, pass_b_prompt, purpose=ModelCapability.REASONING)
usage["sol_onchain_judge_requests" if self.generation_model_hint == "sol" else "qwen_requests"] += 1
pass_c_prompt = "PASS C - DERIVED TOKEN DESIGN. Only if the onchain system needs a native token, derive the minimum token architecture from required protocol functions. Prefer native security bond, endogenous slashable collateral, scarce resource allocation, decentralized security budget, permissionless provider admission, machine economic identity, protocol-specific risk collateral, or required decentralized supply incentives. Weak roles such as payment, discounts, governance, rewards, community, token-gating, treasury, marketing, or alignment cannot justify the token alone. Return JSON with token_thesis, token_utility list, token_demand_loop list, value_capture, security_model, regulatory_risks, required_token_functions, weak_token_functions. If no native token is needed, return token_thesis='No native token required' and token_utility=[]. Problem thesis: " + json.dumps(pass_a, default=str) + " Onchain review: " + json.dumps(pass_b, default=str)
pass_c = self._model_json(self.generation_model_hint, pass_c_prompt, purpose=ModelCapability.REASONING)
usage["sol_token_design_requests" if self.generation_model_hint == "sol" else "qwen_requests"] += 1
payload = {**pass_a, **pass_b, **pass_c, "user_pain": pass_a.get("coordination_failure") or pass_a.get("trust_problem"), "protocol_thesis": pass_a.get("why_neutral_network_may_help") or pass_a.get("product_thesis"), "business_model": pass_a.get("pre_token_revenue_model"), "fee_model": pass_a.get("pre_token_payment_method"), "generation_passes": {"pass_a_problem_network": pass_a, "pass_b_onchain": pass_b, "pass_c_token": pass_c}}
payload = {**pass_a, **pass_b, "token_thesis": "Native token not assessed yet; token utility design runs only after onchain qualification.", "token_utility": [], "token_demand_loop": [], "user_pain": pass_a.get("coordination_failure") or pass_a.get("trust_problem"), "protocol_thesis": pass_a.get("why_neutral_network_may_help") or pass_a.get("product_thesis"), "business_model": pass_a.get("pre_token_revenue_model"), "fee_model": pass_a.get("pre_token_payment_method"), "generation_passes": {"pass_a_problem_network": pass_a, "pass_b_onchain": pass_b}}
return payload, self.generation_model_hint, usage
except Exception:
pass
@ -762,44 +850,43 @@ class CryptoVentureService:
roles = self.token_role_decomposition(proposal)
flags = []
if token.classification in {TokenNecessityClassification.TOKEN_OPTIONAL, TokenNecessityClassification.TOKEN_UNNECESSARY}:
flags.append(TokenRedTeamFlag.TOKEN_NOT_REQUIRED)
flags.append("TOKEN_NOT_REQUIRED")
if onchain.onchain_necessity_score < 70:
flags.append(TokenRedTeamFlag.ONCHAIN_NOT_REQUIRED)
flags.append("REJECT_ONCHAIN_NOT_NEEDED")
if value.value_accrual_quality_score < 65:
flags.append(TokenRedTeamFlag.VALUE_CAPTURE_BROKEN)
flags.append("VALUE_CAPTURE_WEAK")
if value.tokenomics_sustainability_score < 65:
flags.append(TokenRedTeamFlag.UNSUSTAINABLE_EMISSIONS)
flags.append("UNSUSTAINABLE_EMISSIONS")
if policy.regulatory_manageability_score < 55:
flags.append(TokenRedTeamFlag.REGULATORY_RISK_HIGH)
flags.append("LEGAL_COMPLEXITY_OUTWEIGHS_UTILITY")
text = self._proposal_text(proposal)
if "speculat" in text or "apy" in text or "yield farm" in text:
flags.append(TokenRedTeamFlag.SPECULATION_DEPENDENT)
flags.append("SPECULATION_DEPENDENT")
if "governance" in text and "slash" not in text and "fee" not in text:
flags.append(TokenRedTeamFlag.GOVERNANCE_THEATER)
flags.append("GOVERNANCE_ONLY_TOKEN")
if len([role for role, value in roles.roles.items() if value in {TokenRoleRequirement.REQUIRED, TokenRoleRequirement.USEFUL}]) >= 6:
flags.append(TokenRedTeamFlag.TOKEN_DOES_TOO_MUCH)
if roles.roles.get("PAYMENT") in {TokenRoleRequirement.USEFUL, TokenRoleRequirement.OPTIONAL}:
flags.append(TokenRedTeamFlag.NATIVE_PAYMENT_NOT_REQUIRED)
flags.append("TOKEN_DOES_TOO_MUCH")
if roles.roles.get("DEMAND_SIDE_PAYMENT") in {"USEFUL", "OPTIONAL", "REQUIRED", "STRONGLY_USEFUL"} and not any(roles.roles.get(role) in {"REQUIRED", "STRONGLY_USEFUL"} for role in STRUCTURAL_TOKEN_ROLES):
flags.append("PAYMENT_ONLY_TOKEN")
flags.append("NATIVE_PAYMENT_NOT_REQUIRED")
if roles.stablecoin_counterfactual.get("stable_collateral_identical_security"):
flags.append(TokenRedTeamFlag.STABLECOIN_SUBSTITUTE_WORKS)
flags.append(TokenRedTeamFlag.COLLATERAL_CAN_BE_EXTERNAL)
flags.append("COLLATERAL_UTILITY_WEAK")
if any(term in text for term in ["buyback", "revenue share", "profit share"]):
flags.append(TokenRedTeamFlag.REVENUE_CLAIM_LANGUAGE)
flags.append("REVENUE_CLAIM_LANGUAGE")
if "buyback" in text:
flags.append(TokenRedTeamFlag.BUYBACK_DEPENDENCY)
flags.append("BUYBACK_DEPENDENCY")
if "yield" in text or "apy" in text:
flags.append(TokenRedTeamFlag.YIELD_DEPENDENCY)
flags.append("YIELD_DEPENDENCY")
if "manual dispute" in text or "human court" in text:
flags.append(TokenRedTeamFlag.HUMAN_DISPUTE_DEPENDENCY)
flags.append("SLASHING_DEPENDS_ON_HUMAN_JUDGMENT")
if "central operator" in text:
flags.append(TokenRedTeamFlag.CENTRAL_OPERATOR_CONTRADICTION)
flags.append("CENTRAL_OPERATOR_CONTRADICTION")
if "subjective" in text and "slashing" in text:
flags.append(TokenRedTeamFlag.SLASHING_NOT_OBJECTIVELY_MEASURABLE)
sol_review = self._sol_json("Independent Token Red Team V0.2. Return JSON with flags list using only TOKEN_NOT_REQUIRED, SPECULATION_DEPENDENT, UNSUSTAINABLE_EMISSIONS, VALUE_CAPTURE_BROKEN, MERCENARY_INCENTIVES, GOVERNANCE_THEATER, SECURITY_MODEL_WEAK, TOKEN_VELOCITY_TOO_HIGH, BOOTSTRAP_PROBLEM, CENTRALIZATION_CONTRADICTION, REGULATORY_RISK_HIGH, ONCHAIN_NOT_REQUIRED, NO_REAL_USER_DEMAND, TOKEN_DOES_TOO_MUCH, NATIVE_PAYMENT_NOT_REQUIRED, STABLECOIN_SUBSTITUTE_WORKS, COLLATERAL_CAN_BE_EXTERNAL, REVENUE_CLAIM_LANGUAGE, BUYBACK_DEPENDENCY, YIELD_DEPENDENCY, SPECULATIVE_BOOTSTRAP, EMISSIONS_DEPENDENCY, SECURITY_TOKEN_CONCENTRATION, SLASHING_NOT_OBJECTIVELY_MEASURABLE, ORACLE_CIRCULARITY, HUMAN_DISPUTE_DEPENDENCY, CENTRAL_OPERATOR_CONTRADICTION, NETWORK_NOT_READY_FOR_DECENTRALIZATION; severity LOW/MEDIUM/HIGH; critique. Proposal: " + json.dumps(self.crypto_score_context(proposal), default=str))
flags.append("SLASHING_NOT_OBJECTIVE")
sol_review = self._sol_json("Independent Token Red Team V0.3.1. Return JSON with flags list using only TOKEN_DOES_TOO_MUCH, PAYMENT_ONLY_TOKEN, GOVERNANCE_ONLY_TOKEN, REWARD_ONLY_TOKEN, NATIVE_PAYMENT_NOT_REQUIRED, COLLATERAL_UTILITY_WEAK, SLASHING_NOT_OBJECTIVE, SLASHING_DEPENDS_ON_HUMAN_JUDGMENT, TOKEN_SECURITY_NOT_LINKED_TO_PROTOCOL_RISK, SPECULATION_DEPENDENT, REVENUE_CLAIM_LANGUAGE, BUYBACK_DEPENDENCY, YIELD_DEPENDENCY, UNSUSTAINABLE_EMISSIONS, MERCENARY_PROVIDER_INCENTIVES, RESOURCE_ALLOCATION_ARTIFICIAL, MACHINE_IDENTITY_NOT_PORTABLE, VALUE_CAPTURE_WEAK, BOOTSTRAP_REQUIRES_TOKEN_PRICE_GROWTH, CENTRAL_OPERATOR_CONTRADICTION, LEGAL_COMPLEXITY_OUTWEIGHS_UTILITY; severity LOW/MEDIUM/HIGH; critique. Proposal: " + json.dumps(self.crypto_score_context(proposal), default=str))
if sol_review:
for flag in self._as_list(sol_review.get("flags")):
if str(flag) in TokenRedTeamFlag.values:
flags.append(str(flag))
flags.append(str(flag))
severity = "HIGH" if len(flags) >= 3 else "MEDIUM" if flags else "LOW"
if sol_review and str(sol_review.get("severity", "")) in {"LOW", "MEDIUM", "HIGH"}:
severity = str(sol_review["severity"])
@ -841,7 +928,7 @@ class CryptoVentureService:
roles = getattr(proposal, "token_role_decomposition", None) or self.token_role_decomposition(proposal)
base_users = max(1, model.demand_side_users)
tx_per_user = 10
scenario_multipliers = {"LOW_USAGE": 0.3, "EXPECTED": 1.0, "HIGH_USAGE": 3.0, "NO_SUBSIDY": 0.9, "TOKEN_PRICE_DOWN_80": 0.8, "TOKEN_PRICE_UP_10X": 1.2, "PROVIDER_CHURN_50": 0.7, "USER_GROWTH_10X": 10.0, "HIGH_SLASH_RATE": 1.0, "ZERO_EMISSIONS": 1.0, "STABLECOIN_PAYMENT": 1.0, "EXTERNAL_COLLATERAL": 1.0, "NATIVE_TOKEN_REMOVED": 1.0}
scenario_multipliers = {"LOW_USAGE": 0.3, "EXPECTED_USAGE": 1.0, "HIGH_USAGE": 3.0, "NO_SUBSIDY": 0.9, "TOKEN_PRICE_DOWN_80": 0.8, "TOKEN_PRICE_UP_10X": 1.2, "PROVIDER_CHURN_50": 0.7, "USER_GROWTH_10X": 10.0, "HIGH_SLASH_RATE": 1.0, "ZERO_EMISSIONS": 1.0, "STABLECOIN_PAYMENT": 1.0, "ETH_COLLATERAL": 1.0, "USDC_COLLATERAL": 1.0, "NATIVE_TOKEN_REMOVED": 1.0}
for name, multiplier in scenario_multipliers.items():
users = int(base_users * multiplier)
tx = int(users * tx_per_user)
@ -854,10 +941,11 @@ class CryptoVentureService:
provider_supply = max(1, int(provider_supply * 0.45))
staking = max(100, int(staking * 0.45))
native_removed = name == "NATIVE_TOKEN_REMOVED"
stablecoin_substitute = name in {"STABLECOIN_PAYMENT", "EXTERNAL_COLLATERAL"}
protocol_degrades = native_removed and bool(roles.required_roles)
scenarios[name] = {"users": users, "transactions": tx, "fees": fees, "token_demand": 0 if native_removed else fees + staking * 0.01, "provider_supply": provider_supply, "staking": 0 if native_removed else staking, "emissions": emissions, "treasury": round(1000 + fees * model.treasury_share - emissions * 0.1, 2), "circulating_supply": 0 if native_removed else 1_000_000 + emissions, "token_velocity": 0 if native_removed else round(tx / max(1, fees + staking * 0.01), 2), "reward_coverage": round(fees / max(1, emissions), 2), "network_security_budget": 0 if native_removed else staking, "slash_events": round(tx * slash_rate, 2), "stablecoin_payment_works": stablecoin_substitute or roles.roles.get("PAYMENT") != TokenRoleRequirement.REQUIRED, "external_collateral_works": name == "EXTERNAL_COLLATERAL" and roles.stablecoin_counterfactual.get("external_collateral_identical_security"), "protocol_degrades_without_native_token": protocol_degrades}
summary = {"token_price_appreciation_primary_success_variable": False, "subsidy_removed_survives": scenarios["NO_SUBSIDY"]["reward_coverage"] >= 1.0, "native_token_removed_degrades_protocol": scenarios["NATIVE_TOKEN_REMOVED"]["protocol_degrades_without_native_token"], "stablecoin_payment_substitute_works": scenarios["STABLECOIN_PAYMENT"]["stablecoin_payment_works"], "external_collateral_substitute_works": scenarios["EXTERNAL_COLLATERAL"]["external_collateral_works"], "stress_notes": ["Price appreciation is not a success variable.", "If native-token-removed changes little, reduce token necessity."]}
stablecoin_substitute = name in {"STABLECOIN_PAYMENT", "ETH_COLLATERAL", "USDC_COLLATERAL"}
degradation_dimensions = {"SECURITY_DEGRADATION": "SECURITY_BOND" in roles.required_roles or "SLASHABLE_COLLATERAL" in roles.required_roles, "COORDINATION_DEGRADATION": "PROVIDER_ADMISSION" in roles.required_roles, "RESOURCE_ALLOCATION_DEGRADATION": "RESOURCE_ALLOCATION" in roles.required_roles, "BOOTSTRAP_DEGRADATION": "DECENTRALIZED_SUPPLY_COORDINATION" in roles.required_roles, "VALUE_CAPTURE_DEGRADATION": "PROTOCOL_FEE_ASSET" in roles.required_roles, "NETWORK_EFFECT_DEGRADATION": bool(roles.required_roles), "MACHINE_ECONOMIC_DEGRADATION": "MACHINE_ECONOMIC_IDENTITY" in roles.required_roles}
protocol_degrades = native_removed and any(degradation_dimensions.values())
scenarios[name] = {"users": users, "transactions": tx, "fees": fees, "token_demand": 0 if native_removed else fees + staking * 0.01, "provider_supply": provider_supply, "staking": 0 if native_removed else staking, "emissions": emissions, "treasury": round(1000 + fees * model.treasury_share - emissions * 0.1, 2), "circulating_supply": 0 if native_removed else 1_000_000 + emissions, "token_velocity": 0 if native_removed else round(tx / max(1, fees + staking * 0.01), 2), "reward_coverage": round(fees / max(1, emissions), 2), "network_security_budget": 0 if native_removed else staking, "slash_events": round(tx * slash_rate, 2), "stablecoin_payment_works": stablecoin_substitute or roles.roles.get("DEMAND_SIDE_PAYMENT") not in {"REQUIRED", "STRONGLY_USEFUL"}, "external_collateral_works": name in {"ETH_COLLATERAL", "USDC_COLLATERAL"} and roles.stablecoin_counterfactual.get("external_collateral_identical_security"), "protocol_degrades_without_native_token": protocol_degrades, "native_token_removed_degradation_dimensions": degradation_dimensions if native_removed else {}}
summary = {"token_price_appreciation_primary_success_variable": False, "subsidy_removed_survives": scenarios["NO_SUBSIDY"]["reward_coverage"] >= 1.0, "native_token_removed_degrades_protocol": scenarios["NATIVE_TOKEN_REMOVED"]["protocol_degrades_without_native_token"], "native_token_removed_degradation_dimensions": scenarios["NATIVE_TOKEN_REMOVED"]["native_token_removed_degradation_dimensions"], "stablecoin_payment_substitute_works": scenarios["STABLECOIN_PAYMENT"]["stablecoin_payment_works"], "eth_collateral_substitute_works": scenarios["ETH_COLLATERAL"]["external_collateral_works"], "usdc_collateral_substitute_works": scenarios["USDC_COLLATERAL"]["external_collateral_works"], "stress_notes": ["Price appreciation is not a success variable.", "Native-token-removed asks whether protocol becomes materially worse, not literally impossible."]}
return TokenomicsSimulation.objects.update_or_create(proposal=proposal, defaults={"scenarios": scenarios, "summary": summary})[0]
def crypto_scenario_lab(self, cohort: VentureCohort) -> list[CryptoScenarioLab]:
@ -878,6 +966,7 @@ class CryptoVentureService:
roles = getattr(proposal, "token_role_decomposition", None) or self.token_role_decomposition(proposal)
security = getattr(proposal, "protocol_security_assessment", None)
autonomy = self.assess_autonomy(proposal)
utility_profile = token.metadata.get("utility_scores", proposal.metadata.get("crypto", {}).get("token_utility_profile", {})) if isinstance(token.metadata, dict) else {}
text = self._proposal_text(proposal)
component_scores = {
"TOKEN_NECESSITY": token.token_necessity_score,
@ -896,7 +985,7 @@ class CryptoVentureService:
decision = self._crypto_decision(component_scores, token.classification, red.flags)
autonomy_class = CryptoAutonomyClass.AUTONOMOUS_CRYPTO if autonomy.autonomous_operability_score >= 70 else CryptoAutonomyClass.ASSISTED_CRYPTO
counterfactual = token.metadata.get("sol_counterfactual_review", {}) if isinstance(token.metadata, dict) else {}
return {"proposal_id": str(proposal.id), "company": proposal.title, "one_line_thesis": proposal.pitch.get("One-line thesis", ""), "product_thesis": proposal.protocol_thesis.product_thesis, "protocol_thesis": proposal.protocol_thesis.protocol_thesis, "user": proposal.target_customer, "pre_token_business": pretoken.pre_token_business, "pre_token_monetization": pretoken.mode, "pre_token_monetization_potential": pretoken.pre_token_monetization_potential, "pre_token_revenue_ladder": pretoken.revenue_ladder, "protocol_economy": proposal.protocol_thesis.protocol_thesis, "token_economy": proposal.protocol_thesis.token_thesis, "token_thesis": proposal.protocol_thesis.token_thesis, "why_onchain": proposal.onchain_assessment.rationale, "why_token": token.rationale, "token_role_decomposition": roles.roles, "stablecoin_counterfactual": roles.stablecoin_counterfactual, "external_collateral_counterfactual": counterfactual.get("model_c_external_collateral", {}), "native_token_removed_breaks": token.metadata.get("native_token_removed_breaks", []), "native_token_removed_degradation": token.metadata.get("native_token_removed_degradation", ""), "native_token_removed_explanation": token.metadata.get("native_token_removed_explanation", ""), "native_token_removed_outcome": roles.native_token_removed_outcome, "native_token_removed_degrades_protocol": sim.summary.get("native_token_removed_degrades_protocol", False), "token_utility": token.utility_categories, "token_necessity_classification": token.classification, "token_demand_loop": proposal.token_demand_loop.loop, "value_capture": proposal.value_capture.value_accrual, "network_effect": proposal.protocol_thesis.network_effect, "bootstrap_plan": proposal.protocol_thesis.bootstrap_plan, "autonomous_operability": autonomy.autonomous_operability_score, "crypto_autonomy_class": autonomy_class, "regulatory_manageability": policy.regulatory_manageability_score, "security_assessment": security.decision if security else "NOT_ASSESSED", "security_risk": component_scores["SECURITY_MODEL_QUALITY"], "guard_verdict": security.decision if security else "NOT_ASSESSED", "validation_experiment": proposal.validation_plan, "component_scores": component_scores, "value_accrual_quality": value.value_accrual_quality_score, "tokenomics_sustainability": value.tokenomics_sustainability_score, "simulation_summary": sim.summary, "token_red_team_flags": red.flags, "crypto_ic_decision": decision, "crypto_ic_score": score, "research": proposal.metadata.get("research", {}), "research_confidence": proposal.metadata.get("research", {}).get("research_status", "RESEARCH_INSUFFICIENT"), "legal_review_required": policy.legal_review_required}
return {"proposal_id": str(proposal.id), "company": proposal.title, "one_line_thesis": proposal.pitch.get("One-line thesis", ""), "product_thesis": proposal.protocol_thesis.product_thesis, "protocol_thesis": proposal.protocol_thesis.protocol_thesis, "user": proposal.target_customer, "pre_token_business": pretoken.pre_token_business, "pre_token_monetization": pretoken.mode, "pre_token_monetization_potential": pretoken.pre_token_monetization_potential, "pre_token_revenue_ladder": pretoken.revenue_ladder, "protocol_economy": proposal.protocol_thesis.protocol_thesis, "token_economy": proposal.protocol_thesis.token_thesis, "token_thesis": proposal.protocol_thesis.token_thesis, "why_onchain": proposal.onchain_assessment.rationale, "why_token": token.rationale, "token_role_decomposition": roles.roles, "token_utility_scores": utility_profile, "strong_token_roles": token.metadata.get("strong_token_roles", []), "strong_structural_roles": token.metadata.get("strong_structural_roles", []), "argument_for_native_token": token.metadata.get("argument_for_native_token", ""), "argument_against_native_token": token.metadata.get("argument_against_native_token", ""), "stablecoin_counterfactual": roles.stablecoin_counterfactual, "external_collateral_counterfactual": counterfactual.get("model_c_external_collateral", {}), "native_token_removed_breaks": token.metadata.get("native_token_removed_breaks", []), "native_token_removed_degradation": token.metadata.get("native_token_removed_degradation", ""), "native_token_removed_explanation": token.metadata.get("native_token_removed_explanation", ""), "native_token_removed_outcome": roles.native_token_removed_outcome, "native_token_removed_degrades_protocol": sim.summary.get("native_token_removed_degrades_protocol", False), "token_utility": token.utility_categories, "token_necessity_classification": token.classification, "token_demand_loop": proposal.token_demand_loop.loop, "value_capture": proposal.value_capture.value_accrual, "network_effect": proposal.protocol_thesis.network_effect, "bootstrap_plan": proposal.protocol_thesis.bootstrap_plan, "autonomous_operability": autonomy.autonomous_operability_score, "crypto_autonomy_class": autonomy_class, "regulatory_manageability": policy.regulatory_manageability_score, "security_assessment": security.decision if security else "NOT_ASSESSED", "security_risk": component_scores["SECURITY_MODEL_QUALITY"], "guard_verdict": security.decision if security else "NOT_ASSESSED", "validation_experiment": proposal.validation_plan, "component_scores": component_scores, "value_accrual_quality": value.value_accrual_quality_score, "tokenomics_sustainability": value.tokenomics_sustainability_score, "simulation_summary": sim.summary, "token_red_team_flags": red.flags, "crypto_ic_decision": decision, "crypto_ic_score": score, "research": proposal.metadata.get("research", {}), "research_confidence": proposal.metadata.get("research", {}).get("research_status", "RESEARCH_INSUFFICIENT"), "legal_review_required": policy.legal_review_required}
def assess_autonomy(self, proposal: CompanyProposal) -> AutonomousOperabilityAssessment:
assessment = self.venture.assess_autonomous_operability(proposal)
@ -922,19 +1011,21 @@ class CryptoVentureService:
if classification == TokenNecessityClassification.TOKEN_UNNECESSARY:
return CryptoICDecisionType.REJECT_TOKEN_NOT_NEEDED
if classification == TokenNecessityClassification.TOKEN_OPTIONAL:
return CryptoICDecisionType.ROUTE_TO_SAAS
return CryptoICDecisionType.REJECT_TOKEN_UTILITY_WEAK
if TokenRedTeamFlag.SPECULATION_DEPENDENT in flags:
return CryptoICDecisionType.REJECT_SPECULATIVE
if scores["REGULATORY_MANAGEABILITY"] < 55:
return CryptoICDecisionType.REJECT_REGULATORY_RISK
if scores["TOKENOMICS_SUSTAINABILITY"] < 65 or scores["VALUE_ACCRUAL_QUALITY"] < 65:
return CryptoICDecisionType.REVISE_TOKEN_MODEL
if scores["TOKEN_NECESSITY"] >= 85 and scores["ONCHAIN_NECESSITY"] >= 80 and scores["REAL_USAGE_DEMAND"] >= 75 and 55 <= scores["AUTONOMOUS_OPERABILITY"] < 70:
return CryptoICDecisionType.ASSISTED_CRYPTO_HIGH_POTENTIAL
if scores["TOKEN_NECESSITY"] >= 82 and scores["ONCHAIN_NECESSITY"] >= 75:
return CryptoICDecisionType.TESTNET_PILOT
return CryptoICDecisionType.PROTOCOL_VALIDATE
def _sol_final_ic_adjustment(self, row: dict[str, Any]) -> dict[str, Any]:
review = self._sol_json("Final Crypto IC review V0.3. Consider original Sol thesis, independent token counterfactual, Token Red Team, Guard assessment, token economic model, simulation, primary-source evidence, autonomy analysis, pre-token revenue model, and uncertainty. Return JSON with optional score_adjustment -20..20, decision from TESTNET_PILOT, PROTOCOL_VALIDATE, REVISE_TOKEN_MODEL, ROUTE_TO_SAAS, ROUTE_TO_ASSISTED_CRYPTO, WATCHLIST, REJECT_TOKEN_NOT_NEEDED, REJECT_ONCHAIN_NOT_NEEDED, REJECT_SECURITY_MODEL, REJECT_ECONOMIC_MODEL, REJECT_AUTONOMY, REJECT_NO_DEMAND, and rationale. Do not promote weak token ideas or fill finalist slots. Row: " + json.dumps(row, default=str))
review = self._sol_json("Final Crypto IC review V0.3.1. Consider problem thesis, protocol thesis, token utility profile, independent token judge, Token Red Team, Guard assessment, token economic model, simulation, primary-source evidence, autonomy analysis, pre-token business, and uncertainty. Return JSON with optional score_adjustment -20..20, decision from TESTNET_PILOT, PROTOCOL_VALIDATE, REVISE_TOKEN_MODEL, ASSISTED_CRYPTO_HIGH_POTENTIAL, WATCHLIST, ROUTE_TO_VENTURE_STUDIO, REJECT_TOKEN_NOT_NEEDED, REJECT_TOKEN_UTILITY_WEAK, REJECT_ONCHAIN_NOT_NEEDED, REJECT_SECURITY_MODEL, REJECT_ECONOMIC_MODEL, REJECT_AUTONOMY, REJECT_NO_DEMAND, and rationale. Do not promote weak token ideas or fill finalist slots. Row: " + json.dumps(row, default=str))
if not review:
return row
adjustment = max(-20, min(20, float(review.get("score_adjustment", 0))))
@ -945,7 +1036,8 @@ class CryptoVentureService:
def _qualifies_finalist(self, row: dict[str, Any]) -> bool:
scores = row["component_scores"]
return row["token_necessity_classification"] in {TokenNecessityClassification.TOKEN_ESSENTIAL, TokenNecessityClassification.TOKEN_STRONGLY_JUSTIFIED} and scores["TOKEN_NECESSITY"] >= 75 and scores["REAL_USAGE_DEMAND"] >= 65 and scores["ONCHAIN_NECESSITY"] >= 70 and scores["VALUE_ACCRUAL_QUALITY"] >= 65 and scores["TOKENOMICS_SUSTAINABILITY"] >= 65 and scores["AUTONOMOUS_OPERABILITY"] >= 70 and row.get("security_assessment") != ProtocolSecurityDecision.BLOCK_TESTNET and row.get("native_token_removed_degrades_protocol") is True
structural_roles = set(row.get("strong_structural_roles", []))
return row["token_necessity_classification"] in {TokenNecessityClassification.TOKEN_ESSENTIAL, TokenNecessityClassification.TOKEN_STRONGLY_JUSTIFIED} and len(row.get("strong_token_roles", [])) >= 2 and structural_roles & STRUCTURAL_TOKEN_ROLES and scores["TOKEN_NECESSITY"] >= 75 and scores["REAL_USAGE_DEMAND"] >= 65 and scores["ONCHAIN_NECESSITY"] >= 70 and scores["VALUE_ACCRUAL_QUALITY"] >= 65 and scores["TOKENOMICS_SUSTAINABILITY"] >= 65 and scores["AUTONOMOUS_OPERABILITY"] >= 70 and row.get("security_assessment") != ProtocolSecurityDecision.BLOCK_TESTNET and row.get("native_token_removed_degrades_protocol") is True
def _crypto_concentration(self, rows: list[dict[str, Any]]) -> dict[str, Any]:
categories = Counter(row["company"].split()[0] for row in rows)
@ -1021,7 +1113,7 @@ class CryptoVentureService:
return VentureArtifact.objects.create(proposal=proposal, mandate=mandate, graph_run=graph_run, artifact_type=artifact_type, name=name, content=content, readable=readable, generated_by=generated_by)
def _readable_report(self, content: dict[str, Any]) -> str:
lines = ["# CRYPTO VENTURE COHORT V0.3", "", f"Cohort ID: {content['cohort_id']}", f"Crypto survivors: {content['crypto_survivors']}", "", "## Ranking"]
lines = ["# CRYPTO VENTURE COHORT V0.3.1", "", f"Cohort ID: {content['cohort_id']}", f"Crypto survivors: {content['crypto_survivors']}", "", "## Ranking"]
for row in content["ranking"]:
lines.append(f"- Rank {row.get('rank')}: {row['company']} | {row['crypto_ic_decision']} | score {row['crypto_ic_score']} | token {row['token_necessity_classification']}")
lines.append("")

View file

@ -11,7 +11,7 @@ from control_plane.ventures.models import VentureCohort
class Command(BaseCommand):
help = "Export a Crypto Venture Cohort V0.3 report."
help = "Export a Crypto Venture Cohort V0.3.1 report."
def add_arguments(self, parser):
parser.add_argument("--cohort", help="Cohort stable ID or primary key. Defaults to latest crypto cohort.")
@ -64,9 +64,10 @@ class Command(BaseCommand):
f"Cohort ID: `{payload['cohort_id']}`",
f"GraphRun: `{payload['graph_run']}`",
f"Raw protocols generated: `{payload.get('raw_protocols_generated', payload.get('accepted_protocols', 0))}`",
f"Raw Sol theses: `{payload.get('raw_sol_theses', payload.get('raw_protocols_generated', 0))}`. Onchain rejected: `{payload.get('onchain_rejected', 0)}`.",
f"Token unnecessary: `{payload.get('token_unnecessary', 0)}`. Token optional/routed SaaS: `{payload.get('token_optional_routed_saas', 0)}`. Duplicates: `{payload.get('duplicates', 0)}`.",
f"Crypto survivors: `{payload.get('crypto_survivors', 0)}`. Autonomous crypto survivors: `{payload.get('autonomous_crypto_survivors', 0)}`. Security-blocked: `{payload.get('security_blocked', 0)}`. Finalists: `{payload.get('finalists', len(payload.get('top_3', [])))}`.",
f"Raw Sol theses: `{payload.get('raw_sol_theses', payload.get('raw_protocols_generated', 0))}`. Onchain passed: `{payload.get('onchain_passed', 0)}`. Onchain rejected: `{payload.get('onchain_rejected', 0)}`.",
f"Token design attempts: `{payload.get('token_design_attempts', 0)}`. Token design skipped: `{payload.get('token_design_skipped', 0)}`.",
f"Token unnecessary: `{payload.get('token_unnecessary', 0)}`. Token optional/routed SaaS: `{payload.get('token_optional_routed_saas', 0)}`. Token strongly justified: `{payload.get('token_strongly_justified', 0)}`. Token essential: `{payload.get('token_essential', 0)}`. Duplicates: `{payload.get('duplicates', 0)}`.",
f"Crypto survivors: `{payload.get('crypto_survivors', 0)}`. Autonomous crypto survivors: `{payload.get('autonomous_crypto_survivors', 0)}`. Assisted high-potential: `{payload.get('assisted_high_potential', 0)}`. Security-blocked: `{payload.get('security_blocked', 0)}`. Finalists: `{payload.get('finalists', len(payload.get('top_3', [])))}`.",
f"Generation attempts: `{payload['generation_attempts']}`",
"",
"## Runtime",

View file

@ -16,7 +16,7 @@ from model_router.router import ModelRouter
class Command(BaseCommand):
help = "Run a Crypto / Protocol Venture Cohort V0.3."
help = "Run a Crypto / Protocol Venture Cohort V0.3.1."
def add_arguments(self, parser):
parser.add_argument("--size", type=int, default=20)
@ -90,10 +90,16 @@ class Command(BaseCommand):
"raw_protocols_generated": cohort.metrics.get("raw_generated", 0),
"raw_sol_theses": cohort.metrics.get("raw_sol_theses", 0),
"onchain_rejected": cohort.metrics.get("onchain_rejected", 0),
"onchain_passed": cohort.metrics.get("onchain_passed", 0),
"token_design_attempts": cohort.metrics.get("token_design_attempts", 0),
"token_design_skipped": cohort.metrics.get("token_design_skipped_due_to_onchain_rejection", 0),
"token_unnecessary": cohort.metrics.get("token_unnecessary_rejections", 0),
"token_optional_routed_saas": cohort.metrics.get("token_optional_route_to_saas", 0),
"token_strongly_justified": cohort.metrics.get("token_strongly_justified", 0),
"token_essential": cohort.metrics.get("token_essential", 0),
"crypto_survivors": cohort.members.count(),
"autonomous_crypto_survivors": cohort.metrics.get("autonomous_crypto_survivors", 0),
"assisted_high_potential": cohort.metrics.get("assisted_high_potential", 0),
"security_blocked": cohort.metrics.get("protocol_security_gate_blocked", 0),
"finalists": cohort.metrics.get("finalists", 0),
"model_usage": cohort.metrics.get("model_usage", {}),

View file

@ -108,10 +108,13 @@ class CryptoICDecisionType(models.TextChoices):
PROTOCOL_VALIDATE = "PROTOCOL_VALIDATE"
TESTNET_PILOT = "TESTNET_PILOT"
REVISE_TOKEN_MODEL = "REVISE_TOKEN_MODEL"
ASSISTED_CRYPTO_HIGH_POTENTIAL = "ASSISTED_CRYPTO_HIGH_POTENTIAL"
ROUTE_TO_SAAS = "ROUTE_TO_SAAS"
ROUTE_TO_ASSISTED_CRYPTO = "ROUTE_TO_ASSISTED_CRYPTO"
ROUTE_TO_VENTURE_STUDIO = "ROUTE_TO_VENTURE_STUDIO"
WATCHLIST = "WATCHLIST"
REJECT_TOKEN_NOT_NEEDED = "REJECT_TOKEN_NOT_NEEDED"
REJECT_TOKEN_UTILITY_WEAK = "REJECT_TOKEN_UTILITY_WEAK"
REJECT_ONCHAIN_NOT_NEEDED = "REJECT_ONCHAIN_NOT_NEEDED"
REJECT_SECURITY_MODEL = "REJECT_SECURITY_MODEL"
REJECT_SPECULATIVE = "REJECT_SPECULATIVE"

View file

@ -31,7 +31,7 @@ def crypto_venture_cohort_graph_v1() -> ExecutionGraphSpec:
"produce_crypto_cohort_report",
"complete",
]
spec = ExecutionGraphSpec(name="crypto_venture_cohort", version=3, graph_type="CRYPTO_VENTURE_COHORT", entry="prepare_crypto_mandate", nodes={node: GraphNodeSpec(node, node if node == "complete" else f"crypto_venture_{node}") for node in nodes}, edges=[GraphEdgeSpec(nodes[index], nodes[index + 1], "success") for index in range(len(nodes) - 1)], terminal_nodes=["complete"], metadata={"description": "Crypto / Protocol Venture Cohort V0.3: Sol-native problem-first ideation, explicit onchain gate, independent token counterfactual judge, primary-source-first research."})
spec = ExecutionGraphSpec(name="crypto_venture_cohort", version=4, graph_type="CRYPTO_VENTURE_COHORT", entry="prepare_crypto_mandate", nodes={node: GraphNodeSpec(node, node if node == "complete" else f"crypto_venture_{node}") for node in nodes}, edges=[GraphEdgeSpec(nodes[index], nodes[index + 1], "success") for index in range(len(nodes) - 1)], terminal_nodes=["complete"], metadata={"description": "Crypto / Protocol Venture Cohort V0.3.1: Sol-native problem-first ideation, repaired stage ordering, structural native-token utility judge, primary-source-first research."})
spec.validate()
return spec

View file

@ -20,10 +20,12 @@ class SolCryptoReviewProvider(ModelProvider):
payload = {"name": "Machine Identity Credit Union", "one_line_thesis": "Autonomous agents build portable credit histories for machine services.", "product_thesis": "A pre-token API for machine credit and settlement risk scoring.", "user": "AI agent operators", "participants": ["agents", "service providers", "risk observers"], "supply_side": "providers publish measurable service outcomes", "demand_side": "agents need counterparties", "coordination_failure": "portable machine credit is not trusted across operators", "trust_problem": "operators can rewrite private reputation", "why_neutral_network_may_help": "neutral verifiable state lets agents carry economic identity across providers", "pre_token_product": "risk scoring API", "pre_token_customer": "agent operators", "pre_token_value": "lower counterparty default risk", "pre_token_payment_method": "Stripe or stablecoin usage credits", "pre_token_revenue_model": "$100 beta packages", "revenue_1000_path": "10 beta packages", "revenue_5000_path": "20 risk API packages", "revenue_10000_path": "20 subscriptions", "autonomous_operating_loop": "machine demand -> discovery -> settlement -> verification -> reputation update", "bootstrap_plan": "local/testnet simulation", "validation_experiment": "simulate 100 agent jobs", "major_risks": ["token not required"], "confidence": 0.7}
elif "PASS B - ONCHAIN" in prompt:
payload = {"onchain_necessity_score": 86, "why_onchain": "public reputation and escrow materially degrade in private databases", "offchain_substitute": "single operator SaaS", "pass_onchain": True, "reasons": ["verifiable state", "neutral settlement", "machine-to-machine interaction"]}
elif "PASS C - DERIVED TOKEN" in prompt:
elif "PASS C - MINIMAL DECENTRALIZED" in prompt:
payload = {"protocol_architecture": "onchain escrow and public machine credit registry", "participant_model": "agents, providers, risk observers", "verification_model": "objective settlement proofs", "resource_allocation_model": "risk-weighted access", "dispute_model": "automated evidence checks"}
elif "PASS D - NATIVE TOKEN" in prompt:
payload = {"token_thesis": "Native bond represents protocol-specific machine default risk and is slashed for objective settlement failures.", "token_utility": ["protocol-specific collateral", "machine reputation-backed economic participation"], "token_demand_loop": ["agents earn credit", "providers require bond", "defaults slash bond", "reliable agents receive access"], "value_capture": "risk fees and slashing penalties", "security_model": "escrow, timelock, pause, oracle checks, key controls", "regulatory_risks": ["legal review required"], "required_token_functions": ["protocol-specific risk collateral"], "weak_token_functions": ["payment"]}
elif "CRYPTO_TOKEN_COUNTERFACTUAL_JUDGE" in prompt or "Counterfactual token necessity" in prompt:
payload = {"classification": "TOKEN_STRONGLY_JUSTIFIED", "score": 78, "rationale": "Provider staking and slashing materially degrade with database credits.", "fiat_or_database_substitution": "Stablecoin can pay fees but cannot replace bonded slashing and public reputation.", "model_c_external_collateral": {"breaks": "external collateral misses protocol-specific risk"}, "native_token_removed_breaks": ["machine economic identity weakens"], "native_token_removed_degradation": "MATERIAL", "native_token_removed_explanation": "USDC payments work, but protocol-specific bond/reputation does not."}
elif "CRYPTO_TOKEN_UTILITY_JUDGE" in prompt or "CRYPTO_TOKEN_COUNTERFACTUAL_JUDGE" in prompt or "Counterfactual token necessity" in prompt:
payload = {"token_classification": "TOKEN_STRONGLY_JUSTIFIED", "score": 78, "utility_scores": {"SECURITY_UTILITY": 82, "COLLATERAL_UTILITY": 84, "MACHINE_ECONOMIC_UTILITY": 86, "SPECULATION_DEPENDENCE": 10}, "strong_structural_roles": ["SECURITY_BOND", "SLASHABLE_COLLATERAL"], "weak_roles": ["DEMAND_SIDE_PAYMENT"], "counterfactual_analysis": "USDC/ETH can operate but weakens protocol-specific risk pricing.", "material_improvements_over_USDC_ETH": ["protocol-specific default risk", "portable machine economic identity"], "native_asset_costs_and_risks": ["volatility", "legal complexity"], "argument_for_native_token": "Native bond prices protocol-specific machine risk.", "argument_against_native_token": "ETH/USDC collateral is simpler and more liquid.", "final_rationale": "Benefits outweigh costs for protocol-specific collateral.", "model_c_external_collateral": {"breaks": "external collateral misses protocol-specific risk"}, "native_token_removed_breaks": ["machine economic identity weakens"], "native_token_removed_degradation": "MATERIAL", "native_token_removed_explanation": "USDC payments work, but protocol-specific bond/reputation is materially weaker."}
elif "Independent Token Red Team" in prompt:
payload = {"flags": ["BOOTSTRAP_PROBLEM"], "severity": "MEDIUM", "critique": "Provider supply bootstrap remains the main risk."}
elif "Final Crypto IC" in prompt:
@ -62,7 +64,7 @@ def test_crypto_track_and_token_gate_remove_weak_then_regenerate() -> None:
assert weak.status == CompanyProposalStatus.REJECTED
assert weak.metadata["routed_to_saas"] is False
assert cohort.members.count() == 0
assert cohort.metrics["regeneration_policy"].startswith("V0.3")
assert cohort.metrics["regeneration_policy"].startswith("V0.3.1")
def test_v03_sol_problem_first_generation_no_token_in_pass_a_and_onchain_gate() -> None:
@ -79,6 +81,25 @@ def test_v03_sol_problem_first_generation_no_token_in_pass_a_and_onchain_gate()
assert proposal.metadata["crypto"]["problem_first_pass_a_had_no_token"] is True
assert assessment.onchain_necessity_score == 86
assert cohort.metrics["raw_sol_theses"] == 1
assert cohort.metrics["sol_onchain_judge_requests"] == 1
def test_v031_onchain_reject_skips_token_design() -> None:
class RejectOnchainProvider(SolCryptoReviewProvider):
def complete(self, request: ModelRequestContract) -> ModelResponseContract:
if "PASS B - ONCHAIN" in request.prompt:
return ModelResponseContract("sol", json.dumps({"onchain_necessity_score": 40, "pass_onchain": False, "why_onchain": "database is fine"}), {})
return super().complete(request)
svc = sol_service(ModelRouter({"sol": RejectOnchainProvider()}))
cohort = svc.prepare_cohort(size=1, concurrency=1)
svc.generate_protocols(cohort)
svc.onchain_necessity_gate(cohort)
svc.token_necessity_gate(cohort)
assert cohort.metrics["onchain_passed"] == 0
assert cohort.metrics["token_design_attempts"] == 0
assert cohort.metrics["token_design_skipped_due_to_onchain_rejection"] == 1
def test_sol_counterfactual_red_team_and_final_ic_are_used() -> None:
@ -93,7 +114,9 @@ def test_sol_counterfactual_red_team_and_final_ic_are_used() -> None:
review = svc.portfolio_crypto_ic(cohort)
assert token.classification == TokenNecessityClassification.TOKEN_STRONGLY_JUSTIFIED
assert token.metadata["sol_counterfactual_review"]
assert token.metadata["sol_token_utility_judge"]
assert token.metadata["argument_for_native_token"]
assert token.metadata["argument_against_native_token"]
assert TokenRedTeamFlag.BOOTSTRAP_PROBLEM in red.flags
assert review.rankings[0]["sol_final_ic_review"]["score_adjustment"] == 3
@ -119,10 +142,11 @@ def test_tokenomics_simulation_is_proposal_specific() -> None:
low_sim = svc.simulate_tokenomics(low)
high_sim = svc.simulate_tokenomics(high)
assert low_sim.scenarios["EXPECTED"]["users"] != high_sim.scenarios["EXPECTED"]["users"]
assert low_sim.scenarios["EXPECTED"]["token_demand"] != high_sim.scenarios["EXPECTED"]["token_demand"]
assert low_sim.scenarios["EXPECTED_USAGE"]["users"] != high_sim.scenarios["EXPECTED_USAGE"]["users"]
assert low_sim.scenarios["EXPECTED_USAGE"]["token_demand"] != high_sim.scenarios["EXPECTED_USAGE"]["token_demand"]
assert "NATIVE_TOKEN_REMOVED" in low_sim.scenarios
assert "EXTERNAL_COLLATERAL" in low_sim.scenarios
assert "ETH_COLLATERAL" in low_sim.scenarios
assert "USDC_COLLATERAL" in low_sim.scenarios
def test_v03_primary_source_quality_wrong_category_and_weak_coverage() -> None:
@ -187,9 +211,23 @@ def test_v03_independent_counterfactual_native_removed_fields() -> None:
token = svc.assess_token_necessity(proposal)
assert token.metadata["independent_counterfactual_judge"] == "CRYPTO_TOKEN_COUNTERFACTUAL_JUDGE"
assert token.metadata["independent_token_utility_judge"] == "CRYPTO_TOKEN_UTILITY_JUDGE"
assert token.metadata["native_token_removed_degradation"] == "MATERIAL"
assert token.metadata["model_c_external_collateral"]
assert token.metadata["argument_for_native_token"]
def test_v031_payment_governance_reward_only_rejected_but_structural_passes() -> None:
svc = service(ModelRouter({"sol": SolCryptoReviewProvider()}))
cohort = svc.prepare_cohort(size=1, concurrency=1)
weak = svc._create_proposal(cohort.mandate, {"name": "FeeGov Rewards", "product_thesis": "Useful SaaS", "protocol_thesis": "Onchain logs", "token_thesis": "Token is for payment governance and rewards", "token_utility": ["payment", "governance", "rewards"], "token_roles": {"DEMAND_SIDE_PAYMENT": "REQUIRED", "GOVERNANCE": "REQUIRED", "PROVIDER_REWARD": "REQUIRED"}}, "test", "OPEN_CRYPTO_CATEGORY")
strong = svc._create_proposal(cohort.mandate, {**svc._fallback_payload(0, "MACHINE_REPUTATION_WITH_ECONOMIC_STAKE"), "token_roles": {"SECURITY_BOND": "REQUIRED", "SLASHABLE_COLLATERAL": "REQUIRED", "MACHINE_ECONOMIC_IDENTITY": "STRONGLY_USEFUL"}}, "test", "MACHINE_REPUTATION_WITH_ECONOMIC_STAKE")
weak_token = svc.assess_token_necessity(weak)
strong_token = svc.assess_token_necessity(strong)
assert weak_token.classification in {TokenNecessityClassification.TOKEN_OPTIONAL, TokenNecessityClassification.TOKEN_UNNECESSARY}
assert strong_token.classification == TokenNecessityClassification.TOKEN_STRONGLY_JUSTIFIED
assert len(strong_token.metadata["strong_token_roles"]) >= 2
def test_crypto_cohort_graph_real_gates_and_report() -> None:
@ -209,4 +247,6 @@ def test_crypto_cohort_graph_real_gates_and_report() -> None:
assert cohort.metrics["protocol_security_gate_passed"] >= 1
assert len(report.content["ranking"]) <= 3
assert len(report.content["top_3"]) <= 3
assert report.content["title"] == "CRYPTO VENTURE COHORT V0.3"
assert report.content["title"] == "CRYPTO VENTURE COHORT V0.3.1"
if cohort.metrics.get("serious_crypto_survivors", 0) > 0:
assert cohort.metrics["sol_final_ic_requests"] > 0