mw-scenario
Scenario Modifier Middleware
Applies scenario adjustments to base forecasts - enabling what-if analysis and business planning.
Config
# Input: expects 'data' array from previous pipeline step (forecasts)
# Each record should have: item_id, location_id, week, forecast_quantity, lower_bound, upper_bound
scenario: base
custom_adjustments: {}
ttl_seconds: 1800Scenarios
Built-in scenario profiles:
| Scenario | Description | Adjustment |
|---|---|---|
base |
No adjustment | 1.0x |
optimistic |
Growth assumptions | 1.15x |
pessimistic |
Conservative outlook | 0.85x |
promotional |
Planned promotions | 1.30x during promo weeks |
disruption |
Supply chain issues | 0.70x |
custom |
User-defined | Per config |
Fetch
import json
from datetime import datetime
# Config is unified: node config + pipeline params + session context
# PipelineProvider loads and merges these automatically
scenario_name = config.get('scenario', 'base')
custom_adj = config.get('custom_adjustments', {})
# Input data comes from previous pipeline step (accumulated context)
input_data = config.get('data', [])
if not input_data:
raise ValueError("No input data - mw-scenario requires 'data' from previous pipeline step")
# Built-in scenario multipliers
SCENARIOS = {
'base': lambda week, item: 1.0,
'optimistic': lambda week, item: 1.15,
'pessimistic': lambda week, item: 0.85,
'promotional': lambda week, item: 1.30 if week % 4 == 0 else 1.0, # Promo every 4th week
'disruption': lambda week, item: 0.70,
}
def get_multiplier(scenario, week, item_id):
"""Get scenario multiplier for a given week and item."""
if scenario == 'custom':
# Custom allows per-item or per-week overrides
item_mult = custom_adj.get('items', {}).get(item_id, 1.0)
week_mult = custom_adj.get('weeks', {}).get(str(week), 1.0)
return item_mult * week_mult
return SCENARIOS.get(scenario, SCENARIOS['base'])(week, item_id)
# Apply scenario adjustments
scenario_forecasts = []
for record in input_data:
adj_record = record.copy()
item_id = record.get('item_id')
week = record.get('horizon_period', 1)
multiplier = get_multiplier(scenario_name, week, item_id)
# Store original forecast
adj_record['base_forecast'] = record.get('forecast_quantity', 0)
adj_record['base_lower'] = record.get('lower_bound', 0)
adj_record['base_upper'] = record.get('upper_bound', 0)
# Apply scenario adjustment
adj_record['scenario'] = scenario_name
adj_record['scenario_multiplier'] = multiplier
adj_record['adjusted_forecast'] = round(record.get('forecast_quantity', 0) * multiplier)
adj_record['adjusted_lower'] = round(record.get('lower_bound', 0) * multiplier)
adj_record['adjusted_upper'] = round(record.get('upper_bound', 0) * multiplier)
scenario_forecasts.append(adj_record)
# Build result with full provenance
result = {
'data': scenario_forecasts,
'meta': {
'generated_at': datetime.utcnow().isoformat(),
'stage': 'scenario',
'scenario': scenario_name,
'input_count': len(input_data),
'output_count': len(scenario_forecasts),
'source': 'mw-scenario'
}
}
print(json.dumps(result, indent=2))❌ Fence Execution Error: No input data - mw-scenario requires 'data' from previous pipeline step Traceback (most recent call last): File "/app/oculus/providers/python_provider.py", line 468, in execute exec(fence_content, exec_globals, exec_locals) File "
", line 12, in ValueError: No input data - mw-scenario requires 'data' from previous pipeline step
Usage
Base Scenario (Pass-through)
oculus exec scenarioOptimistic Planning
scenario: optimisticCustom Adjustments
scenario: custom
custom_adjustments:
items:
ITEM-001: 1.20 # 20% boost for specific item
ITEM-002: 0.90 # 10% reduction
weeks:
"5": 1.50 # 50% boost in week 5 (planned sale)
"10": 0.60 # 40% reduction in week 10 (supplier issue)Diffing Scenarios
Run multiple scenarios and compare:
# Generate base and optimistic
oculus exec scenario --config '{"scenario": "base"}' > base.json
oculus exec scenario --config '{"scenario": "optimistic"}' > optimistic.json
# Diff becomes an edge
diff base.json optimistic.jsonThe diff between scenario outputs reveals:
- Impact magnitude: How much does the scenario change things?
- Risk exposure: Which items are most sensitive?
- Planning buffer: Range between pessimistic and optimistic
Pipeline Position
Raw Data → Seasonality → Trend → Forecast → [Scenario] → Output
↑
You are hereThis is the final middleware in the core pipeline. Downstream consumers get scenario-adjusted forecasts with full provenance chain.
Provenance
Document
- Status: 🔴 Unverified
Changelog
- 2026-01-25 19:11: Node created by mcp - Fourth middleware node completing the forecast pipeline - applies scenario adjustments (optimistic/pessimistic/promotional/custom) to base forecasts
North
slots:
- slug: mw-forecast
context:
- 'Pipeline flow: forecast feeds into scenario modifier'
↑ northmw-forecast