Dry-Run Feature Modularity Audit & Expansion Plan¶
Executive Summary¶
This document provides a comprehensive audit of the existing dry-run feature's modularity and outlines a strategic plan for expanding it across other capabilities, particularly co-sell relationships and partner management workflows.
Part 1: Current Implementation Audit¶
1.1 Architecture Overview¶
The dry-run feature currently consists of four main components:
| Component | Location | Responsibility |
|---|---|---|
| DryRunService | app/Extensions/AiPresentation/System/Services/DryRunService.php |
AI-powered question generation, persona management, prompt building |
| AiPresentation Model | app/Extensions/AiPresentation/System/Models/AiPresentation.php |
History storage, session management |
| Controller Endpoints | app/Extensions/AiPresentation/System/Http/Controllers/AiPresentationController.php |
API routes for config, generation, history, deletion |
| View Component | app/Extensions/AiPresentation/resources/views/home/dry-run-modal.blade.php |
Alpine.js-based UI with tabs for config/results/history |
1.2 Modularity Strengths¶
- Separation of Concerns: Service layer properly isolated from controller logic
- Configuration Management: Static methods (
getPersonas(),getIndustries(), etc.) centralize config data - Quality Tiers: Configurable AI model selection based on quality level (quick/standard/deep)
- Clean API Design: RESTful endpoints follow Laravel conventions
- Frontend Encapsulation: Alpine.js component manages all state independently
1.3 Modularity Weaknesses (Tight Coupling)¶
| Issue | Impact | Severity |
|---|---|---|
History storage hardcoded to AiPresentation model |
Cannot reuse for other entities | High |
| No shared interfaces or traits | Cannot compose with other features | High |
| Personas/industries hardcoded in PHP arrays | Cannot customize per organization | Medium |
| Max 10 sessions hardcoded (line 107) | No configurability | Low |
| Prompt building presentation-specific | Cannot reuse for proposals/co-sell | High |
| No analytics or persistence beyond JSON | Cannot analyze patterns | Medium |
1.4 Current Data Flow¶
┌─────────────────────────────────────────────────────────────────┐
│ Current Flow │
├─────────────────────────────────────────────────────────────────┤
│ │
│ User Config (persona, industry, quality) │
│ ↓ │
│ Controller validates → DryRunService.generateQuestions() │
│ ↓ │
│ buildPrompt() → BedrockRuntimeService.invokeModel() │
│ ↓ │
│ parseResponse() → AiPresentation.addDryRunToHistory() │
│ ↓ │
│ JSON stored in dry_run_history column │
│ │
└─────────────────────────────────────────────────────────────────┘
Part 2: Expansion Opportunities¶
2.1 Co-Sell Relationship Dry-Run Use Cases¶
The most valuable expansion is into co-sell workflows. Here's a detailed breakdown:
A. Pre-Partnership Assessment¶
Scenario: Before formalizing a co-sell relationship with a partner
| Persona | Questions to Simulate |
|---|---|
| Alliance Manager | "What's your AWS certification status?" "How does your solution complement ours?" |
| Partner Development | "What's your customer overlap?" "What's your co-sell track record?" |
| Technical Reviewer | "Is your solution AWS-native?" "What integration points exist?" |
Value: Identify partnership risks before committing resources
B. Brand Voice Merger Simulation¶
Scenario: Testing if two brands work together before content creation
| Simulation Type | Output |
|---|---|
| Brand Alignment Score | 0-100 compatibility rating |
| Messaging Preview | Sample merged messaging |
| Conflict Detection | Areas where brands clash |
Value: Avoid content rework and brand conflicts
C. Approval Workflow Testing¶
Scenario: Predicting approval bottlenecks before campaign launch
| Simulation Type | Output |
|---|---|
| Timeline Forecast | Days to publish estimate |
| Bottleneck Identification | Which partner/stage delays |
| Rejection Prediction | Likelihood of rework cycles |
Value: Set realistic expectations and resource allocation
D. Publishing Coordination Dry-Run¶
Scenario: Testing multi-channel publishing before going live
| Simulation Type | Output |
|---|---|
| Channel Mix Optimization | Best platform combination |
| Schedule Validation | Timing and offset verification |
| Failure Scenario Testing | Retry logic validation |
Value: Ensure coordinated execution without real-world failures
E. Proposal Approval Simulation¶
Scenario: Testing CPPO proposal viability before submission
| Simulation Type | Output |
|---|---|
| Approval Probability | Likelihood score with reasoning |
| Margin Analysis | Impact on portfolio profitability |
| Risk Identification | Deal-specific risk factors |
| Stakeholder Path | Required approvals and decision makers |
Value: Don't waste effort on proposals unlikely to approve
2.2 Additional Capability Opportunities¶
| Capability | Dry-Run Benefit |
|---|---|
| Competitive Battlecards | Simulate competitor objections before sales calls |
| Analyst Briefing Prep | Practice analyst questions before briefings |
| Partner Pitch Decks | Rehearse partner manager questions |
| Email Sequences | Forecast engagement without damaging reputation |
| Event Follow-Up | Practice follow-up conversation scenarios |
Part 3: Modular Architecture Design¶
3.1 Proposed Interface Contracts¶
<?php
namespace App\Contracts\DryRun;
/**
* Contract for entities that support dry-run simulation
*/
interface SimulatableInterface
{
/**
* Get the content/context for simulation
*/
public function getSimulationContext(): array;
/**
* Add a simulation session to history
*/
public function addSimulationToHistory(SimulationResult $result): void;
/**
* Get simulation history
*/
public function getSimulationHistory(): array;
/**
* Get available personas for this entity type
*/
public static function getAvailablePersonas(): array;
/**
* Get maximum history sessions to retain
*/
public function getMaxHistorySessions(): int;
}
/**
* Contract for simulation services
*/
interface SimulationServiceInterface
{
/**
* Run a simulation
*/
public function simulate(
SimulatableInterface $entity,
SimulationConfig $config
): SimulationResult;
/**
* Get available configuration options
*/
public function getConfigurationOptions(): array;
/**
* Validate configuration before simulation
*/
public function validateConfig(array $config): bool;
}
3.2 Proposed Trait for History Management¶
<?php
namespace App\Traits;
use App\Contracts\DryRun\SimulationResult;
trait HasSimulationHistory
{
/**
* Add simulation to history
*/
public function addSimulationToHistory(SimulationResult $result): void
{
$history = $this->simulation_history ?? [];
$history[] = [
'id' => uniqid('sim_'),
'created_at' => now()->toIso8601String(),
'type' => $result->getType(),
'config' => $result->getConfig(),
'result' => $result->getData(),
];
// Keep only last N sessions
$maxSessions = $this->getMaxHistorySessions();
if (count($history) > $maxSessions) {
$history = array_slice($history, -$maxSessions);
}
$this->simulation_history = $history;
$this->save();
}
/**
* Get simulation history
*/
public function getSimulationHistory(): array
{
return $this->simulation_history ?? [];
}
/**
* Get count of simulation sessions
*/
public function getSimulationCountAttribute(): int
{
return count($this->simulation_history ?? []);
}
/**
* Delete a specific simulation session
*/
public function deleteSimulation(string $simulationId): bool
{
$history = $this->simulation_history ?? [];
$newHistory = array_filter($history, fn($s) => $s['id'] !== $simulationId);
if (count($newHistory) === count($history)) {
return false; // Not found
}
$this->simulation_history = array_values($newHistory);
$this->save();
return true;
}
/**
* Default max sessions - can be overridden
*/
public function getMaxHistorySessions(): int
{
return 10;
}
}
3.3 Proposed Base Simulation Service¶
<?php
namespace App\Services\DryRun;
use App\Contracts\DryRun\SimulatableInterface;
use App\Contracts\DryRun\SimulationServiceInterface;
use App\Services\Bedrock\BedrockRuntimeService;
abstract class BaseSimulationService implements SimulationServiceInterface
{
protected BedrockRuntimeService $bedrockService;
protected const QUALITY_MODELS = [
'quick' => 'us.anthropic.claude-3-5-haiku-20241022-v1:0',
'standard' => 'us.anthropic.claude-3-5-sonnet-20241022-v2:0',
'deep' => 'us.anthropic.claude-3-opus-20240229-v1:0',
];
protected const QUALITY_CONFIG = [
'quick' => ['max_tokens' => 2000, 'temperature' => 0.7],
'standard' => ['max_tokens' => 3000, 'temperature' => 0.8],
'deep' => ['max_tokens' => 4000, 'temperature' => 0.85],
];
public function __construct(BedrockRuntimeService $bedrockService)
{
$this->bedrockService = $bedrockService;
}
/**
* Template method for simulation
*/
public function simulate(
SimulatableInterface $entity,
SimulationConfig $config
): SimulationResult {
$this->validateConfig($config->toArray());
$prompt = $this->buildPrompt($entity, $config);
$response = $this->invokeAI($prompt, $config->quality);
$parsed = $this->parseResponse($response);
return new SimulationResult(
type: $this->getSimulationType(),
config: $config->toArray(),
data: $parsed
);
}
/**
* Invoke AI model with quality-specific settings
*/
protected function invokeAI(string $prompt, string $quality): string
{
$modelId = self::QUALITY_MODELS[$quality] ?? self::QUALITY_MODELS['standard'];
$config = self::QUALITY_CONFIG[$quality] ?? self::QUALITY_CONFIG['standard'];
return $this->bedrockService->invokeModel($modelId, $prompt, $config);
}
/**
* Parse JSON response from AI
*/
protected function parseResponse(string $response): array
{
$response = preg_replace('/^```json\s*/m', '', $response);
$response = preg_replace('/\s*```$/m', '', $response);
$parsed = json_decode(trim($response), true);
return json_last_error() === JSON_ERROR_NONE ? $parsed : [];
}
/**
* Must be implemented by concrete services
*/
abstract protected function buildPrompt(
SimulatableInterface $entity,
SimulationConfig $config
): string;
abstract protected function getSimulationType(): string;
}
3.4 Proposed Directory Structure¶
app/
├── Contracts/
│ └── DryRun/
│ ├── SimulatableInterface.php
│ ├── SimulationServiceInterface.php
│ ├── SimulationConfig.php
│ └── SimulationResult.php
├── Traits/
│ └── HasSimulationHistory.php
├── Services/
│ └── DryRun/
│ ├── BaseSimulationService.php
│ ├── Config/
│ │ ├── PersonaRegistry.php # Centralized persona management
│ │ ├── IndustryRegistry.php # Centralized industry data
│ │ └── QualityConfig.php # Quality level configuration
│ ├── Simulators/
│ │ ├── PresentationSimulator.php # Migrated from DryRunService
│ │ ├── CoSellSimulator.php # New
│ │ ├── ProposalSimulator.php # New
│ │ ├── ApprovalWorkflowSimulator.php # New
│ │ └── PartnershipSimulator.php # New
│ └── Prompts/
│ ├── PresentationPromptBuilder.php
│ ├── CoSellPromptBuilder.php
│ └── ProposalPromptBuilder.php
└── Extensions/
├── AiPresentation/
│ └── System/
│ └── Models/
│ └── AiPresentation.php # Uses HasSimulationHistory trait
└── ContentManager/
└── System/
└── Models/
├── CoSellPlan.php # Add HasSimulationHistory trait
└── CoSellRelationship.php # Add HasSimulationHistory trait
Part 4: Co-Sell Dry-Run Implementation Details¶
4.1 CoSellSimulator Service¶
<?php
namespace App\Services\DryRun\Simulators;
use App\Contracts\DryRun\SimulatableInterface;
use App\Services\DryRun\BaseSimulationService;
class CoSellSimulator extends BaseSimulationService
{
protected function getSimulationType(): string
{
return 'co_sell_preparation';
}
public static function getAvailablePersonas(): array
{
return [
'alliance_manager' => [
'name' => 'AWS Alliance Manager',
'icon' => 'handshake',
'focus' => ['partnership value', 'AWS alignment', 'co-sell potential', 'deal support'],
'description' => 'Evaluates partnership strength and AWS marketplace alignment',
],
'partner_development' => [
'name' => 'Partner Development Manager',
'icon' => 'users',
'focus' => ['partner enablement', 'training needs', 'certification', 'go-to-market'],
'description' => 'Assesses partner readiness and enablement requirements',
],
'deal_desk' => [
'name' => 'Deal Desk / Pricing',
'icon' => 'calculator',
'focus' => ['margin requirements', 'pricing approval', 'deal structure', 'compliance'],
'description' => 'Reviews deal economics and pricing compliance',
],
'legal_compliance' => [
'name' => 'Legal & Compliance',
'icon' => 'shield-check',
'focus' => ['contract terms', 'liability', 'IP protection', 'regulatory compliance'],
'description' => 'Evaluates legal and compliance requirements',
],
'technical_reviewer' => [
'name' => 'Technical Solution Reviewer',
'icon' => 'code',
'focus' => ['integration quality', 'AWS best practices', 'security posture', 'scalability'],
'description' => 'Validates technical implementation and architecture',
],
];
}
public static function getPartnershipStages(): array
{
return [
'prospecting' => [
'name' => 'Prospecting / Initial Outreach',
'concerns' => ['fit assessment', 'initial value prop', 'partnership criteria'],
],
'evaluation' => [
'name' => 'Evaluation / Due Diligence',
'concerns' => ['technical validation', 'business model alignment', 'reference checks'],
],
'negotiation' => [
'name' => 'Negotiation / Contracting',
'concerns' => ['terms alignment', 'pricing structure', 'SLA requirements'],
],
'onboarding' => [
'name' => 'Onboarding / Enablement',
'concerns' => ['training completion', 'certification', 'go-to-market readiness'],
],
'active' => [
'name' => 'Active Partnership',
'concerns' => ['deal flow', 'relationship health', 'growth opportunities'],
],
];
}
protected function buildPrompt(
SimulatableInterface $entity,
SimulationConfig $config
): string
{
$context = $entity->getSimulationContext();
$persona = self::getAvailablePersonas()[$config->persona];
$stage = self::getPartnershipStages()[$config->stage ?? 'evaluation'];
return <<<PROMPT
You are simulating a {$persona['name']} evaluating a co-sell partnership opportunity.
## YOUR PERSONA
**Role:** {$persona['name']}
**Focus Areas:** {$this->formatArray($persona['focus'])}
**Description:** {$persona['description']}
## PARTNERSHIP STAGE
**Stage:** {$stage['name']}
**Key Concerns:** {$this->formatArray($stage['concerns'])}
## PARTNERSHIP CONTEXT
**Partner A:** {$context['partner_a']['name']}
**Partner B:** {$context['partner_b']['name']}
**Proposed Value:** {$context['value_proposition']}
## YOUR TASK
Generate challenging questions this persona would ask to validate this co-sell partnership.
Return JSON:
{
"questions": [
{
"question": "...",
"category": "business_fit|technical|legal|financial|operational",
"difficulty": "easy|medium|hard",
"intent": "What you're really evaluating",
"red_flags": "What would concern you in the answer"
}
],
"partnership_risks": [
{
"risk": "Specific risk this persona would identify",
"mitigation": "How to address this risk",
"severity": "low|medium|high"
}
],
"success_criteria": [
"What would make this partnership succeed from your perspective"
],
"recommended_next_steps": [
"Actions to take before proceeding"
]
}
PROMPT;
}
}
4.2 Co-Sell Specific Personas¶
| Persona | Focus Areas | Key Questions |
|---|---|---|
| AWS Alliance Manager | Co-sell potential, AWS alignment | "What's your AWS certification level?" "How does this accelerate marketplace revenue?" |
| Partner Development Manager | Enablement, training | "What training do your sellers need?" "How quickly can you be deal-ready?" |
| Deal Desk | Pricing, margins | "What's the margin split?" "Does this meet approval thresholds?" |
| Legal/Compliance | Contracts, liability | "Who owns the customer relationship?" "What's the IP arrangement?" |
| Technical Reviewer | Architecture, integration | "Is this Well-Architected compliant?" "What's the integration complexity?" |
4.3 Database Migration¶
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
// Add simulation_history to co_sell_plans
Schema::table('co_sell_plans', function (Blueprint $table) {
$table->json('simulation_history')->nullable()->after('status');
});
// Add simulation_history to co_sell_relationships
Schema::table('co_sell_relationships', function (Blueprint $table) {
$table->json('simulation_history')->nullable()->after('health_score');
});
}
public function down(): void
{
Schema::table('co_sell_plans', function (Blueprint $table) {
$table->dropColumn('simulation_history');
});
Schema::table('co_sell_relationships', function (Blueprint $table) {
$table->dropColumn('simulation_history');
});
}
};
Part 5: Implementation Roadmap¶
Phase 1: Foundation (Week 1-2)¶
- Create
SimulatableInterfaceandSimulationResultcontracts - Create
HasSimulationHistorytrait - Create
BaseSimulationServiceabstract class - Create
PersonaRegistryandIndustryRegistryconfig classes - Migrate
DryRunServiceto use new architecture (backwards compatible)
Phase 2: Co-Sell Integration (Week 3-4)¶
- Add
simulation_historymigration forco_sell_plansandco_sell_relationships - Implement
CoSellSimulatorservice - Add
HasSimulationHistorytrait toCoSellPlanandCoSellRelationshipmodels - Create API endpoints for co-sell simulation
- Build co-sell dry-run UI component
Phase 3: Proposal Simulation (Week 5)¶
- Implement
ProposalSimulatorfor CPPO proposals - Add approval prediction logic
- Integrate with existing proposal workflow
Phase 4: Analytics & Optimization (Week 6)¶
- Add simulation analytics tracking
- Build simulation history dashboard
- Implement pattern detection across simulations
Part 6: Value Assessment Matrix¶
6.1 Priority Ranking¶
| Capability | Business Value | Implementation Effort | Priority |
|---|---|---|---|
| Co-Sell Partnership Prep | High - Risk mitigation | Medium | P1 |
| CPPO Proposal Approval | High - Deal velocity | Medium | P1 |
| Brand Voice Validation | Medium - Content quality | Low | P2 |
| Approval Workflow Testing | Medium - Process efficiency | Medium | P2 |
| Publishing Dry-Run | Low - Already simulated | Low | P3 |
| Email Sequence Testing | Medium - Reputation protection | Medium | P3 |
6.2 ROI Estimates¶
| Use Case | Without Dry-Run | With Dry-Run | Savings |
|---|---|---|---|
| Failed partnership (discovered late) | $50K+ in wasted effort | Early identification | ~$40K/partnership |
| Proposal rejection (discovered at submission) | 2-3 week delay | Preemptive fixes | 2+ weeks/deal |
| Brand conflict (discovered in campaign) | Campaign restart | Upfront validation | ~$10K/campaign |
| Approval bottleneck | Unpredictable timelines | Forecasted delays | Resource optimization |
Part 7: Technical Considerations¶
7.1 Performance¶
- Simulation calls use Bedrock AI - ~5-30 seconds depending on quality level
- History stored as JSON - efficient for small datasets, consider separate table at scale
- Frontend uses Alpine.js - minimal bundle impact
7.2 Security¶
- All simulations authenticated via middleware
- No PII in simulation prompts (use entity references, not raw data)
- History deletion available for data hygiene
7.3 Scalability¶
- JSON column limits: ~1GB per row (PostgreSQL), ~4GB (MySQL)
- 10 sessions × ~50KB average = ~500KB per entity - well within limits
- Consider archival to S3 for historical analysis at scale
Part 8: Success Metrics¶
8.1 Adoption Metrics¶
- Simulations per entity type per month
- Unique users running simulations
- Simulation-to-action conversion rate
8.2 Quality Metrics¶
- Simulation accuracy (predicted vs actual outcomes)
- User satisfaction scores
- Time saved per workflow
8.3 Business Impact¶
- Partnership success rate improvement
- Proposal approval rate improvement
- Time-to-market reduction for co-sell campaigns
Appendix A: Current File References¶
| File | Path | Key Lines |
|---|---|---|
| DryRunService | app/Extensions/AiPresentation/System/Services/DryRunService.php |
78-299 (configs), 304-374 (generate), 379-481 (prompt) |
| AiPresentation Model | app/Extensions/AiPresentation/System/Models/AiPresentation.php |
80-113 (history methods) |
| Controller | app/Extensions/AiPresentation/System/Http/Controllers/AiPresentationController.php |
398-522 (endpoints) |
| Routes | app/Extensions/AiPresentation/System/AiPresentationServiceProvider.php |
126-130 (route definitions) |
| View | app/Extensions/AiPresentation/resources/views/home/dry-run-modal.blade.php |
Full file (811 lines) |
Appendix B: Co-Sell Services Reference¶
| Service | Path | Dry-Run Opportunity |
|---|---|---|
| ApprovalWorkflowService | app/Extensions/ContentManager/System/Services/CoSell/ApprovalWorkflowService.php |
Approval timeline simulation |
| BrandVoiceMerger | app/Extensions/ContentManager/System/Services/CoSell/BrandVoiceMerger.php |
Brand compatibility testing |
| CoSellAnalyticsService | app/Extensions/ContentManager/System/Services/CoSell/CoSellAnalyticsService.php |
Performance forecasting |
| CrossPartnerPublishingService | app/Extensions/ContentManager/System/Services/CoSell/CrossPartnerPublishingService.php |
Publishing coordination testing |
| EmailFunnelService | app/Extensions/ContentManager/System/Services/CoSell/EmailFunnelService.php |
Engagement forecasting |
| CppoProposalGeneratorCapability | app/Extensions/ContentManager/System/Services/Capabilities/CppoProposalGeneratorCapability.php |
Proposal approval prediction |
Document generated: 2025-12-31 Author: Claude Code Audit