membra-underwriter / liquidification_layer.py
josephrw's picture
Upload liquidification_layer.py with huggingface_hub
f17696c verified
Raw
History Blame Contribute Delete
34.5 kB
#!/usr/bin/env python3
"""
Liquidification Layer - Finding the practical path to cash.
Liquidification means the product always asks: How does this asset move toward cash?
For each asset, it should generate a route:
- Sell as standalone codebase
- Package as micro-SaaS
- Turn into hosted API
- Turn into Hugging Face Space
- License to strategic buyer
- Sell as data/report package
- Submit to IP broker
- Submit to venture studio
- Submit to accelerator
- Offer to software M&A buyer
- Open-source with paid services
- Bundle with related repos
- Archive as non-financeable
Then it should assign:
- Expected buyer category
- Expected sale difficulty
- Expected sale timeline
- Expected forced-sale range
- Required cleanup before outreach
- Best next action
This is how the system stops being a dashboard and becomes a monetization operator.
"""
from enum import Enum
from typing import Dict, Any, List, Optional, Tuple
from dataclasses import dataclass, field
from datetime import datetime
import json
class LiquidationRoute(Enum):
"""Monetization routes for software assets."""
STANDALONE_CODEBASE_SALE = "standalone_codebase_sale"
MICRO_SAAS = "micro_saas"
HOSTED_API = "hosted_api"
HUGGING_FACE_SPACE = "hugging_face_space"
STRATEGIC_LICENSE = "strategic_license"
DATA_REPORT_PACKAGE = "data_report_package"
IP_BROKER_SUBMISSION = "ip_broker_submission"
VENTURE_STUDIO_SUBMISSION = "venture_studio_submission"
ACCELERATOR_SUBMISSION = "accelerator_submission"
SOFTWARE_MA_BUYER = "software_ma_buyer"
OPEN_SOURCE_PAID_SERVICES = "open_source_paid_services"
BUNDLE_WITH_REPOS = "bundle_with_repos"
ARCHIVE_NON_FINANCEABLE = "archive_non_financeable"
class BuyerCategory(Enum):
"""Categories of potential buyers."""
DEVELOPER_TOOLING_BUYERS = "developer_tooling_buyers"
IP_CONSULTANTS = "ip_consultants"
VENTURE_STUDIOS = "venture_studios"
SOFTWARE_MA_ADVISORS = "software_ma_advisors"
CORPORATE_ACQUIRERS = "corporate_acquirers"
PRIVATE_EQUITY = "private_equity"
STRATEGIC_BUYERS = "strategic_buyers"
MARKETPLACES = "marketplaces"
BROKERS = "brokers"
ACCELERATORS = "accelerators"
class SaleDifficulty(Enum):
"""Expected difficulty of sale."""
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
VERY_HIGH = "very_high"
@dataclass
class LiquidificationPlan:
"""
A complete liquidification plan for an asset.
Answers: How does this asset move toward cash?
"""
asset_id: str
primary_route: LiquidationRoute
alternative_routes: List[LiquidationRoute]
# Buyer information
expected_buyer_category: BuyerCategory
buyer_universe: List[str] # Specific buyer names or types
# Sale expectations
sale_difficulty: SaleDifficulty
expected_timeline_days: Tuple[int, int] # (min, max)
expected_price_range: Tuple[float, float] # (min, max) in USD
# Requirements
required_cleanup: List[str]
required_packaging: List[str]
# Action
best_next_action: str
action_priority: str # immediate, short_term, long_term
# Metadata
confidence: float # 0-1
generated_at: datetime = field(default_factory=datetime.now)
def to_dict(self) -> Dict[str, Any]:
return {
"asset_id": self.asset_id,
"primary_route": self.primary_route.value,
"alternative_routes": [route.value for route in self.alternative_routes],
"expected_buyer_category": self.expected_buyer_category.value,
"buyer_universe": self.buyer_universe,
"sale_difficulty": self.sale_difficulty.value,
"expected_timeline_days": list(self.expected_timeline_days),
"expected_price_range": list(self.expected_price_range),
"required_cleanup": self.required_cleanup,
"required_packaging": self.required_packaging,
"best_next_action": self.best_next_action,
"action_priority": self.action_priority,
"confidence": self.confidence,
"generated_at": self.generated_at.isoformat(),
}
class LiquidificationEngine:
"""
Liquidification Engine - Generates monetization routes.
This is how the system becomes a monetization operator, not just a dashboard.
"""
def __init__(self):
self.route_criteria = {
LiquidationRoute.STANDALONE_CODEBASE_SALE: {
"min_production_grade": "B",
"min_collateral_grade": "C",
"requires": ["clear_ownership", "no_secrets", "buildable"],
},
LiquidationRoute.MICRO_SAAS: {
"min_production_grade": "A-",
"min_commercial_grade": "B",
"requires": ["api_potential", "scalable", "market_fit"],
},
LiquidationRoute.HOSTED_API: {
"min_production_grade": "B+",
"min_execution_score": 70,
"requires": ["api_endpoints", "deployable", "documentation"],
},
LiquidationRoute.HUGGING_FACE_SPACE: {
"min_production_grade": "C",
"requires": ["ml_model", "demo_ready", "documentation"],
},
LiquidationRoute.STRATEGIC_LICENSE: {
"min_production_grade": "B",
"min_commercial_grade": "B",
"requires": ["clear_license", "strategic_value", "ip_clarity"],
},
LiquidationRoute.DATA_REPORT_PACKAGE: {
"min_production_grade": "C",
"requires": ["data_value", "analysis_capability", "report_generation"],
},
LiquidationRoute.IP_BROKER_SUBMISSION: {
"min_production_grade": "B",
"min_collateral_grade": "B",
"requires": ["clear_ownership", "market_value", "documentation"],
},
LiquidationRoute.VENTURE_STUDIO_SUBMISSION: {
"min_production_grade": "B-",
"min_commercial_grade": "B-",
"requires": ["growth_potential", "scalable", "market_fit"],
},
LiquidationRoute.ACCELERATOR_SUBMISSION: {
"min_production_grade": "C+",
"requires": ["prototype", "team", "vision"],
},
LiquidationRoute.SOFTWARE_MA_BUYER: {
"min_production_grade": "A-",
"min_collateral_grade": "B+",
"requires": ["production_ready", "revenue", "clear_ownership"],
},
LiquidationRoute.OPEN_SOURCE_PAID_SERVICES: {
"min_production_grade": "B",
"requires": ["community", "support_model", "documentation"],
},
LiquidationRoute.BUNDLE_WITH_REPOS: {
"min_production_grade": "C",
"requires": ["related_assets", "synergy", "packaging"],
},
}
def generate_liquidification_plan(
self,
asset_data: Dict[str, Any],
grades: Dict[str, Any],
committee_results: Dict[str, Any],
) -> LiquidificationPlan:
"""
Generate a complete liquidification plan.
Args:
asset_data: Asset metadata and classification
grades: Professional grades
committee_results: Committee evaluation results
Returns:
LiquidificationPlan with monetization strategy
"""
# Determine eligible routes
eligible_routes = self._determine_eligible_routes(asset_data, grades, committee_results)
# Select primary route
primary_route = self._select_primary_route(eligible_routes, asset_data, grades)
# Determine buyer category
buyer_category = self._determine_buyer_category(primary_route, asset_data, grades)
# Generate buyer universe
buyer_universe = self._generate_buyer_universe(buyer_category, asset_data)
# Estimate sale difficulty
sale_difficulty = self._estimate_sale_difficulty(primary_route, grades, committee_results)
# Estimate timeline
timeline = self._estimate_timeline(primary_route, sale_difficulty, grades)
# Estimate price range
price_range = self._estimate_price_range(grades, committee_results, asset_data)
# Determine required cleanup
required_cleanup = self._determine_required_cleanup(committee_results, asset_data)
# Determine required packaging
required_packaging = self._determine_required_packaging(primary_route, asset_data)
# Generate best next action
best_next_action = self._generate_best_next_action(
primary_route,
required_cleanup,
required_packaging,
grades,
)
# Determine action priority
action_priority = self._determine_action_priority(
primary_route,
required_cleanup,
grades,
)
# Calculate confidence
confidence = self._calculate_confidence(grades, committee_results)
return LiquidificationPlan(
asset_id=asset_data.get("asset_id", "unknown"),
primary_route=primary_route,
alternative_routes=[r for r in eligible_routes if r != primary_route],
expected_buyer_category=buyer_category,
buyer_universe=buyer_universe,
sale_difficulty=sale_difficulty,
expected_timeline_days=timeline,
expected_price_range=price_range,
required_cleanup=required_cleanup,
required_packaging=required_packaging,
best_next_action=best_next_action,
action_priority=action_priority,
confidence=confidence,
)
def _determine_eligible_routes(
self,
asset_data: Dict[str, Any],
grades: Dict[str, Any],
committee_results: Dict[str, Any],
) -> List[LiquidationRoute]:
"""Determine which liquidation routes are eligible."""
eligible = []
production_grade = grades.get("production_grade", "F")
commercial_grade = grades.get("commercial_grade", "F")
collateral_grade = grades.get("collateral_grade", "F")
execution_score = grades.get("execution_proof", 0)
# Check for risk blocks
risk_blocked = committee_results.get("committee_report", {}).get("risk_blocked", False)
for route, criteria in self.route_criteria.items():
# Skip if risk blocked (except archive)
if risk_blocked and route != LiquidationRoute.ARCHIVE_NON_FINANCEABLE:
continue
# Check production grade
min_prod = criteria.get("min_production_grade", "F")
if not self._grade_meets_minimum(production_grade, min_prod):
continue
# Check commercial grade if required
min_comm = criteria.get("min_commercial_grade")
if min_comm and not self._grade_meets_minimum(commercial_grade, min_comm):
continue
# Check collateral grade if required
min_coll = criteria.get("min_collateral_grade")
if min_coll and not self._grade_meets_minimum(collateral_grade, min_coll):
continue
# Check execution score if required
min_exec = criteria.get("min_execution_score")
if min_exec and execution_score < min_exec:
continue
# Check asset-specific requirements
if not self._check_route_requirements(route, asset_data):
continue
eligible.append(route)
# Always add archive as fallback
if LiquidationRoute.ARCHIVE_NON_FINANCEABLE not in eligible:
eligible.append(LiquidationRoute.ARCHIVE_NON_FINANCEABLE)
return eligible
def _grade_meets_minimum(self, grade: str, minimum: str) -> bool:
"""Check if grade meets minimum requirement."""
grade_order = ["F", "D", "C-", "C", "C+", "B-", "B", "B+", "A-", "A", "A+"]
try:
grade_idx = grade_order.index(grade)
min_idx = grade_order.index(minimum)
return grade_idx >= min_idx
except ValueError:
return False
def _check_route_requirements(self, route: LiquidationRoute, asset_data: Dict[str, Any]) -> bool:
"""Check route-specific requirements."""
criteria = self.route_criteria[route]
required = criteria.get("requires", [])
for requirement in required:
if requirement == "clear_ownership":
if not asset_data.get("has_ownership_clarity", False):
return False
elif requirement == "no_secrets":
if asset_data.get("secrets_detected", []):
return False
elif requirement == "buildable":
if asset_data.get("build_status") != "passed":
return False
elif requirement == "api_potential":
if not asset_data.get("has_api_potential", False):
return False
elif requirement == "scalable":
if not asset_data.get("is_scalable", False):
return False
elif requirement == "market_fit":
if not asset_data.get("has_market_fit", False):
return False
elif requirement == "api_endpoints":
if not asset_data.get("has_endpoints", False):
return False
elif requirement == "deployable":
if asset_data.get("deployment_status") not in ["deployed", "deployable"]:
return False
elif requirement == "documentation":
if not asset_data.get("has_documentation", False):
return False
elif requirement == "ml_model":
if asset_data.get("asset_type") != "model":
return False
elif requirement == "demo_ready":
if not asset_data.get("has_demo", False):
return False
elif requirement == "clear_license":
if not asset_data.get("has_license", False):
return False
elif requirement == "strategic_value":
if not asset_data.get("has_strategic_value", False):
return False
elif requirement == "ip_clarity":
if not asset_data.get("has_ownership_clarity", False):
return False
elif requirement == "data_value":
if not asset_data.get("has_data_value", False):
return False
elif requirement == "analysis_capability":
if not asset_data.get("has_analysis_capability", False):
return False
elif requirement == "report_generation":
if not asset_data.get("has_report_generation", False):
return False
elif requirement == "market_value":
if grades := asset_data.get("grades"):
if grades.get("commercial_grade") in ["D", "F"]:
return False
elif requirement == "growth_potential":
if not asset_data.get("has_growth_potential", False):
return False
elif requirement == "revenue":
if not asset_data.get("revenue_evidence", []):
return False
elif requirement == "community":
if not asset_data.get("has_community", False):
return False
elif requirement == "support_model":
if not asset_data.get("has_support_model", False):
return False
elif requirement == "related_assets":
if not asset_data.get("related_assets", []):
return False
elif requirement == "synergy":
if not asset_data.get("has_synergy", False):
return False
elif requirement == "packaging":
if not asset_data.get("is_packagable", False):
return False
elif requirement == "prototype":
classification = asset_data.get("classification", "")
if "prototype" not in classification.lower():
return False
elif requirement == "team":
if not asset_data.get("has_team", False):
return False
elif requirement == "vision":
if not asset_data.get("has_vision", False):
return False
elif requirement == "production_ready":
if grades := asset_data.get("grades"):
if grades.get("production_grade") not in ["A", "B"]:
return False
return True
def _select_primary_route(
self,
eligible_routes: List[LiquidationRoute],
asset_data: Dict[str, Any],
grades: Dict[str, Any],
) -> LiquidationRoute:
"""Select the primary liquidification route."""
if not eligible_routes:
return LiquidationRoute.ARCHIVE_NON_FINANCEABLE
# Priority order for route selection
priority_order = [
LiquidationRoute.SOFTWARE_MA_BUYER,
LiquidationRoute.MICRO_SAAS,
LiquidationRoute.HOSTED_API,
LiquidationRoute.STRATEGIC_LICENSE,
LiquidationRoute.STANDALONE_CODEBASE_SALE,
LiquidationRoute.IP_BROKER_SUBMISSION,
LiquidationRoute.VENTURE_STUDIO_SUBMISSION,
LiquidationRoute.HUGGING_FACE_SPACE,
LiquidationRoute.DATA_REPORT_PACKAGE,
LiquidationRoute.OPEN_SOURCE_PAID_SERVICES,
LiquidationRoute.BUNDLE_WITH_REPOS,
LiquidationRoute.ACCELERATOR_SUBMISSION,
LiquidationRoute.ARCHIVE_NON_FINANCEABLE,
]
# Select highest priority eligible route
for route in priority_order:
if route in eligible_routes:
return route
return eligible_routes[0]
def _determine_buyer_category(
self,
route: LiquidationRoute,
asset_data: Dict[str, Any],
grades: Dict[str, Any],
) -> BuyerCategory:
"""Determine the expected buyer category."""
route_to_category = {
LiquidationRoute.STANDALONE_CODEBASE_SALE: BuyerCategory.DEVELOPER_TOOLING_BUYERS,
LiquidationRoute.MICRO_SAAS: BuyerCategory.STRATEGIC_BUYERS,
LiquidationRoute.HOSTED_API: BuyerCategory.DEVELOPER_TOOLING_BUYERS,
LiquidationRoute.HUGGING_FACE_SPACE: BuyerCategory.MARKETPLACES,
LiquidationRoute.STRATEGIC_LICENSE: BuyerCategory.STRATEGIC_BUYERS,
LiquidationRoute.DATA_REPORT_PACKAGE: BuyerCategory.IP_CONSULTANTS,
LiquidationRoute.IP_BROKER_SUBMISSION: BuyerCategory.BROKERS,
LiquidationRoute.VENTURE_STUDIO_SUBMISSION: BuyerCategory.VENTURE_STUDIOS,
LiquidationRoute.ACCELERATOR_SUBMISSION: BuyerCategory.ACCELERATORS,
LiquidationRoute.SOFTWARE_MA_BUYER: BuyerCategory.SOFTWARE_MA_ADVISORS,
LiquidationRoute.OPEN_SOURCE_PAID_SERVICES: BuyerCategory.DEVELOPER_TOOLING_BUYERS,
LiquidationRoute.BUNDLE_WITH_REPOS: BuyerCategory.DEVELOPER_TOOLING_BUYERS,
LiquidationRoute.ARCHIVE_NON_FINANCEABLE: BuyerCategory.DEVELOPER_TOOLING_BUYERS,
}
return route_to_category.get(route, BuyerCategory.DEVELOPER_TOOLING_BUYERS)
def _generate_buyer_universe(
self,
buyer_category: BuyerCategory,
asset_data: Dict[str, Any],
) -> List[str]:
"""Generate a list of potential buyers."""
category = asset_data.get("category", "unknown")
buyer_universes = {
BuyerCategory.DEVELOPER_TOOLING_BUYERS: [
"Developer tooling companies",
"IDE vendors",
"Code platform providers",
"DevOps tool companies",
],
BuyerCategory.IP_CONSULTANTS: [
"IP consulting firms",
"Technology transfer offices",
"Patent licensing firms",
"IP brokers",
],
BuyerCategory.VENTURE_STUDIOS: [
"Venture studios",
"Startup accelerators",
"Corporate innovation labs",
"Technology incubators",
],
BuyerCategory.SOFTWARE_MA_ADVISORS: [
"Software M&A advisors",
"Technology investment banks",
"Private equity tech funds",
"Strategic acquirers",
],
BuyerCategory.CORPORATE_ACQUIRERS: [
"Fortune 500 tech acquirers",
"Corporate development teams",
"Strategic buyers",
],
BuyerCategory.PRIVATE_EQUITY: [
"Tech-focused PE firms",
"Growth equity funds",
"Buyout funds",
],
BuyerCategory.STRATEGIC_BUYERS: [
"Competitors in adjacent markets",
"Platform companies",
"Strategic acquirers",
],
BuyerCategory.MARKETPLACES: [
"Hugging Face",
"GitHub Marketplace",
"NPM/PyPI ecosystem",
"API marketplaces",
],
BuyerCategory.BROKERS: [
"IP brokers",
"Technology brokers",
"Software asset brokers",
],
BuyerCategory.ACCELERATORS: [
"Y Combinator",
"Techstars",
"Industry-specific accelerators",
"Corporate accelerators",
],
}
universe = buyer_universes.get(buyer_category, ["General software buyers"])
# Add category-specific buyers
if category == "machine_learning":
universe.extend(["ML platform companies", "AI infrastructure firms"])
elif category == "developer_tools":
universe.extend(["IDE vendors", "DevOps companies"])
elif category == "fintech":
universe.extend(["Fintech acquirers", "Banks"])
return universe
def _estimate_sale_difficulty(
self,
route: LiquidationRoute,
grades: Dict[str, Any],
committee_results: Dict[str, Any],
) -> SaleDifficulty:
"""Estimate the difficulty of sale."""
financeability = grades.get("financeability_score", 0)
commercial_grade = grades.get("commercial_grade", "F")
# Check for blockers
blockers = committee_results.get("committee_report", {}).get("all_blockers", [])
if blockers:
return SaleDifficulty.VERY_HIGH
if financeability >= 80 and commercial_grade in ["A", "B"]:
return SaleDifficulty.LOW
elif financeability >= 60 and commercial_grade in ["B", "C"]:
return SaleDifficulty.MEDIUM
elif financeability >= 40:
return SaleDifficulty.HIGH
else:
return SaleDifficulty.VERY_HIGH
def _estimate_timeline(
self,
route: LiquidationRoute,
difficulty: SaleDifficulty,
grades: Dict[str, Any],
) -> Tuple[int, int]:
"""Estimate sale timeline in days."""
base_timelines = {
LiquidationRoute.STANDALONE_CODEBASE_SALE: (30, 90),
LiquidationRoute.MICRO_SAAS: (60, 180),
LiquidationRoute.HOSTED_API: (30, 60),
LiquidationRoute.HUGGING_FACE_SPACE: (7, 30),
LiquidationRoute.STRATEGIC_LICENSE: (60, 180),
LiquidationRoute.DATA_REPORT_PACKAGE: (14, 45),
LiquidationRoute.IP_BROKER_SUBMISSION: (30, 90),
LiquidationRoute.VENTURE_STUDIO_SUBMISSION: (30, 90),
LiquidationRoute.ACCELERATOR_SUBMISSION: (30, 60),
LiquidationRoute.SOFTWARE_MA_BUYER: (90, 180),
LiquidationRoute.OPEN_SOURCE_PAID_SERVICES: (90, 365),
LiquidationRoute.BUNDLE_WITH_REPOS: (30, 90),
LiquidationRoute.ARCHIVE_NON_FINANCEABLE: (0, 0),
}
base_min, base_max = base_timelines.get(route, (30, 90))
# Adjust based on difficulty
difficulty_multiplier = {
SaleDifficulty.LOW: 1.0,
SaleDifficulty.MEDIUM: 1.5,
SaleDifficulty.HIGH: 2.0,
SaleDifficulty.VERY_HIGH: 3.0,
}
multiplier = difficulty_multiplier.get(difficulty, 1.5)
return (int(base_min * multiplier), int(base_max * multiplier))
def _estimate_price_range(
self,
grades: Dict[str, Any],
committee_results: Dict[str, Any],
asset_data: Dict[str, Any],
) -> Tuple[float, float]:
"""Estimate price range in USD."""
financeability = grades.get("financeability_score", 0)
# Base price ranges based on financeability
if financeability >= 80:
base_min, base_max = 50000, 500000
elif financeability >= 60:
base_min, base_max = 25000, 250000
elif financeability >= 40:
base_min, base_max = 10000, 100000
elif financeability >= 20:
base_min, base_max = 5000, 50000
else:
base_min, base_max = 0, 10000
# Adjust based on revenue evidence
revenue_evidence = asset_data.get("revenue_evidence", [])
if revenue_evidence:
base_max *= 2
# Adjust based on strategic value
if asset_data.get("has_strategic_value", False):
base_max *= 1.5
return (base_min, base_max)
def _determine_required_cleanup(
self,
committee_results: Dict[str, Any],
asset_data: Dict[str, Any],
) -> List[str]:
"""Determine required cleanup before monetization."""
cleanup = []
blockers = committee_results.get("committee_report", {}).get("all_blockers", [])
for blocker in blockers:
if "secret" in blocker.lower():
cleanup.append("Remove all secrets and use environment variables")
elif "private key" in blocker.lower():
cleanup.append("Remove all private keys")
elif "ownership" in blocker.lower():
cleanup.append("Clarify ownership through documentation")
elif "license" in blocker.lower():
cleanup.append("Add appropriate license file")
elif "build" in blocker.lower():
cleanup.append("Fix build issues")
elif "scaffold" in blocker.lower():
cleanup.append("Remove scaffolding and retain custom work")
# Add standard cleanup if needed
if not asset_data.get("has_documentation", False):
cleanup.append("Add comprehensive documentation")
if asset_data.get("build_status") != "passed":
cleanup.append("Ensure build passes")
return cleanup if cleanup else ["No critical cleanup required"]
def _determine_required_packaging(
self,
route: LiquidationRoute,
asset_data: Dict[str, Any],
) -> List[str]:
"""Determine required packaging for the route."""
packaging = []
route_packaging = {
LiquidationRoute.STANDALONE_CODEBASE_SALE: [
"Create sale packet with technical documentation",
"Prepare code transfer documentation",
"Generate usage examples",
],
LiquidationRoute.MICRO_SAAS: [
"Package as deployable SaaS",
"Create pricing model",
"Prepare hosting infrastructure",
],
LiquidationRoute.HOSTED_API: [
"Package as API service",
"Create API documentation",
"Set up hosting",
],
LiquidationRoute.HUGGING_FACE_SPACE: [
"Prepare model for Hugging Face",
"Create demo notebook",
"Write model card",
],
LiquidationRoute.STRATEGIC_LICENSE: [
"Prepare licensing terms",
"Document IP rights",
"Create license agreement template",
],
LiquidationRoute.DATA_REPORT_PACKAGE: [
"Package data with documentation",
"Create report template",
"Document data sources",
],
LiquidationRoute.IP_BROKER_SUBMISSION: [
"Create IP summary",
"Prepare valuation report",
"Document ownership chain",
],
LiquidationRoute.VENTURE_STUDIO_SUBMISSION: [
"Create pitch deck",
"Document growth metrics",
"Prepare team information",
],
LiquidationRoute.ACCELERATOR_SUBMISSION: [
"Create application materials",
"Document prototype status",
"Prepare team information",
],
LiquidationRoute.SOFTWARE_MA_BUYER: [
"Create comprehensive diligence packet",
"Prepare financial documentation",
"Document technical architecture",
],
LiquidationRoute.OPEN_SOURCE_PAID_SERVICES: [
"Prepare open-source release",
"Define support model",
"Create pricing for services",
],
LiquidationRoute.BUNDLE_WITH_REPOS: [
"Identify related assets",
"Create bundle documentation",
"Define bundle pricing",
],
LiquidationRoute.ARCHIVE_NON_FINANCEABLE: [
"Document archival decision",
"Create summary record",
],
}
return route_packaging.get(route, ["Prepare standard packaging"])
def _generate_best_next_action(
self,
route: LiquidationRoute,
required_cleanup: List[str],
required_packaging: List[str],
grades: Dict[str, Any],
) -> str:
"""Generate the single best next action."""
# If critical cleanup needed, that's the action
critical_cleanup = [c for c in required_cleanup if "secret" in c.lower() or "private key" in c.lower()]
if critical_cleanup:
return f"CRITICAL: {critical_cleanup[0]}"
# If cleanup needed, do that first
if required_cleanup and "No critical cleanup required" not in required_cleanup:
return f"Complete cleanup: {required_cleanup[0]}"
# If packaging needed, do that
if required_packaging:
return f"Complete packaging: {required_packaging[0]}"
# Route-specific actions
route_actions = {
LiquidationRoute.STANDALONE_CODEBASE_SALE: "Prepare sale packet and begin outreach to developer tooling buyers",
LiquidationRoute.MICRO_SAAS: "Deploy as SaaS and begin customer acquisition",
LiquidationRoute.HOSTED_API: "Deploy API and create integration documentation",
LiquidationRoute.HUGGING_FACE_SPACE: "Upload to Hugging Face and promote in community",
LiquidationRoute.STRATEGIC_LICENSE: "Identify strategic buyers and prepare licensing terms",
LiquidationRoute.DATA_REPORT_PACKAGE: "Package data and reach out to IP consultants",
LiquidationRoute.IP_BROKER_SUBMISSION: "Submit to IP broker with valuation report",
LiquidationRoute.VENTURE_STUDIO_SUBMISSION: "Apply to venture studios with pitch deck",
LiquidationRoute.ACCELERATOR_SUBMISSION: "Apply to relevant accelerators",
LiquidationRoute.SOFTWARE_MA_BUYER: "Engage software M&A advisor and prepare diligence packet",
LiquidationRoute.OPEN_SOURCE_PAID_SERVICES: "Release as open-source and define support services",
LiquidationRoute.BUNDLE_WITH_REPOS: "Identify related repos and create bundle package",
LiquidationRoute.ARCHIVE_NON_FINANCEABLE: "Archive asset and focus on higher-priority projects",
}
return route_actions.get(route, "Review and refine asset for monetization")
def _determine_action_priority(
self,
route: LiquidationRoute,
required_cleanup: List[str],
grades: Dict[str, Any],
) -> str:
"""Determine action priority."""
critical_cleanup = [c for c in required_cleanup if "secret" in c.lower() or "private key" in c.lower()]
if critical_cleanup:
return "immediate"
if required_cleanup and "No critical cleanup required" not in required_cleanup:
return "immediate"
financeability = grades.get("financeability_score", 0)
if financeability >= 70:
return "immediate"
elif financeability >= 50:
return "short_term"
else:
return "long_term"
def _calculate_confidence(
self,
grades: Dict[str, Any],
committee_results: Dict[str, Any],
) -> float:
"""Calculate confidence in the liquidification plan."""
financeability = grades.get("financeability_score", 0)
# Higher financeability = higher confidence
base_confidence = financeability / 100
# Reduce confidence if risk blocked
if committee_results.get("committee_report", {}).get("risk_blocked", False):
base_confidence *= 0.5
return min(1.0, max(0.3, base_confidence))