Skip to content

feat: add full economics modeling for IntelIP scenarios#40

Merged
hudsonaikins merged 2 commits into
mainfrom
codex/profitctl-full-economics-pass
Apr 13, 2026
Merged

feat: add full economics modeling for IntelIP scenarios#40
hudsonaikins merged 2 commits into
mainfrom
codex/profitctl-full-economics-pass

Conversation

@hudsonaikins
Copy link
Copy Markdown
Contributor

@hudsonaikins hudsonaikins commented Apr 13, 2026

Summary

  • add full-economics cost-layer modeling and reporting across CLI, JSON, markdown, and simulation output
  • support IntelIP scenario packs for conservative, target, stress, paid-pilot, tight-free, and workspace-minimum rollout analysis
  • extend pricing/config/cost validation and tests for mix pricing, workspace-hybrid pricing, paid-user-scoped costs, and related regression fixtures

Testing

  • go test ./...

Greptile Summary

This PR adds a full-economics cost-layer model (delivery / productization / adoption) to ProfitCtl, extending the config schema, cost engine, simulation, and all output surfaces (CLI, JSON, Markdown). It also ships a complete IntelIP scenario pack — six YAML files covering conservative, target, stress, paid-pilot, tight-free, and workspace-minimum rollout shapes — together with calibration notes and a tooling cost inventory.

  • P1 – Four mix-mode scenario files cannot be parsed: intelip_ops_conservative.yml, intelip_ops_target.yml, intelip_ops_stress.yml, and intelip_rollout_tight_free.yml all include limits.users on their plans. validateMixPricing explicitly rejects any plan with a non-nil Limits in mix mode, so ParseConfig returns a validation error for each of these files. The two workspace-hybrid scenarios are unaffected.
  • P2 – Potential double-counting in FullEconomicsSummary: buildFullEconomicsSummary adds paymentFees.Total to both DeliveryCost and TotalCost. If a future config combines a payment_fees: YAML block with a user_scope: paid_users variable cost for the same fee, the amount is counted twice. The current scenario files avoid this by using only the variable-cost approach, but the risk is undocumented.

Confidence Score: 4/5

Safe to merge after fixing the mix-mode limits validation conflict that blocks four of the six new scenario files.

The Go engine changes are clean and well-tested. One P1 defect blocks the primary user-facing deliverable of this PR (running the IntelIP scenario pack): four mix-mode YAML files include limits that the validator rejects. This needs to be resolved before the scenario files are usable.

The four mix-mode scenario files (intelip_ops_conservative.yml, intelip_ops_target.yml, intelip_ops_stress.yml, intelip_rollout_tight_free.yml) and internal/config/validator.go (the validateMixPricing function).

Important Files Changed

Filename Overview
benchmark_scenarios/intelip_ops_conservative.yml New IntelIP conservative scenario; includes limits on mix-mode plans which the validator rejects — the file cannot be parsed/run as-is.
benchmark_scenarios/intelip_ops_target.yml New IntelIP target scenario; same limits-in-mix-mode validation failure as conservative.
benchmark_scenarios/intelip_ops_stress.yml New IntelIP stress scenario; same limits-in-mix-mode validation failure.
benchmark_scenarios/intelip_rollout_tight_free.yml New tight-free rollout scenario; same limits-in-mix-mode validation failure.
internal/config/validator.go Adds validateMixPricing, validateWorkspaceHybridPricing, and validatePricingPlanCohort; the mix validator explicitly rejects limits on plans, which conflicts with the new scenario files.
cmd/simulation_runner.go Adds buildFullEconomicsSummary helper and wires cfg.Pricing into scale/stress simulation calls; potential double-counting of payment fees when both variable-cost and payment_fees section are used together.
internal/output/json.go Adds pointer-guarded full_economics block to JSON output; populated only when TotalCost > 0.
pkg/types/cost.go Introduces EconomicsLayer, EconomicsAllocationMode, VariableCostUserScope types with backward-compatible normalization helpers; well-structured.
pkg/types/structures.go Extends FixedCost and VariableCost with EconomicsLayer and Allocation; adds EconomicsLayerBreakdown with Add and Round helpers.
internal/pricing/calculator.go Adds calculateMixRevenue and calculateWorkspaceHybridRevenue; share allocation with deterministic rounding is correct.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: benchmark_scenarios/intelip_ops_conservative.yml
Line: 226-264

Comment:
**`limits` in `mix` mode fails validation**

`validateMixPricing` in `internal/config/validator.go` (line ~228) explicitly rejects any plan that has a non-nil `Limits` field:

```go
if plan.Limits != nil {
    return fmt.Errorf("pricing mode mix does not support limits on plan %s: %w", …)
}
```

All four new `mix`-mode YAML scenario files (`conservative`, `target`, `stress`, `tight_free`) include a `limits.users` block on every plan. Calling `ParseConfig` on any of them returns a validation error — so `go run . simulate -f benchmark_scenarios/intelip_ops_conservative.yml` (and the equivalent for the other three) will fail immediately, regardless of the comment in `intelip_ops_pricing_pack.md` that says "`limits.users` can still be carried for reference."

Fix options:
1. **Remove the `limits` blocks** from the four scenario files (they are ignored by `calculateMixRevenue` anyway), or
2. **Relax the validator** to allow `limits` in `mix` mode when a `share` is also present, treating them as documentation metadata only.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: cmd/simulation_runner.go
Line: 1271-1289

Comment:
**Payment fees double-counted when both sources are active**

`buildFullEconomicsSummary` adds `paymentFees.Total` to both `DeliveryCost` and `TotalCost`:

```go
DeliveryCost: totalCosts.GrandByEconomicsLayer.Delivery + paymentFees.Total,
TotalCost:    totalCosts.GrandTotal + paymentFees.Total,
```

`totalCosts.GrandTotal` already includes variable costs whose `economics_layer` defaults to `delivery` — and the new scenario files model Stripe fees exactly this way (a `user_scope: paid_users` variable cost). If a future config combines that variable-cost approach with a `payment_fees:` YAML block, `paymentFees.Total` would add the structured fee on top of the variable cost that already covers it, inflating both `DeliveryCost` and `TotalCost`.

Consider documenting that these two mechanisms are mutually exclusive for payment-fee modeling, or add a guard in `buildFullEconomicsSummary` that only adds `paymentFees.Total` when the variable costs do not already contain a `paid_users`-scoped fee line.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "chore: address PR cleanup feedback" | Re-trigger Greptile

Comment thread internal/output/json.go
Comment thread internal/config/parser.go Outdated
Comment thread internal/config/validator.go
@hudsonaikins hudsonaikins merged commit 6305a05 into main Apr 13, 2026
3 checks passed
@hudsonaikins hudsonaikins deleted the codex/profitctl-full-economics-pass branch April 13, 2026 19:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant