You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-**Q2 — Decyzja 2 wdrażana teraz.** Usługi spoza tabeli burn-rate w scenariuszu `pool` księgują przychód przez `calculateMonetizationRevenue`, tak jak dziś `plan`/`feature`/`pack`. To odblokowuje wzorzec "tylko Fable w puli, Sonnet obok" bez czekania na sublimity (Q4).
45
45
-**Q3 — jawna `overage_price_per_credit` odłożona.** Floor kosztowy + EVC z ADR 0010 Decyzja 1 zostaje jedynym mechanizmem cenowym nadwyżki; z pustym EVC już dziś poprawnie daje pass-through bez marży.
46
46
-**Q4 — sublimity per usługa w puli odłożone (YAGNI).** Do czasu realnego przypadku z >1 usługą w jednej puli i nierównym podziałem limitu.
Po wdrożeniu Decyzji 1 (`fee_basis: 'per_member'`) drugi przebieg tego samego żywego scenariusza (Claude Pro + pula Fable, `c6d297d3-…`) ujawnił dwie kolejne luki, obie w tym samym miejscu — założeniu, że "opłata subskrypcyjna" i "wliczony limit" mają tę samą bazę co `aiUsers`:
51
+
52
+
1.**`per_member` liczy fee po adopterach, nie po całej bazie płacącej.**`aiUsers` (`ai_adoption_rate × current_users`) to populacja **korzystająca z AI**, nie populacja **płacąca abonament**. Dla Claude Pro każdy z 1M subskrybentów płaci $20, niezależnie od tego, czy w danym miesiącu w ogóle użył Fable — `fee_basis: 'per_member'` na scenariuszu z `ai_adoption_rate: 0.3` liczyłby fee od 300k, zaniżając przychód ~3,3×.
53
+
2.**`credit_pool_size` jest absolutne — nie ma sposobu wyrazić "2,5 kredytu wliczone NA UŻYTKOWNIKA".** Realna polityka Anthropic to allowance *per subskrybent*, nie jeden wspólny worek kredytów na całą kohortę. Przy stałym `credit_pool_size` allowance efektywnie znika przy milionowej bazie (limit wyczerpuje się natychmiast, cała konsumpcja Fable księguje się jako nadwyżka pass-through) — więc nie da się odtworzyć podstawowej mechaniki "pierwsze 2,5 kredytu na koszt firmy, reszta pass-through per user".
54
+
55
+
Root cause dodatkowo pogłębiony przez bug implementacyjny: loader scenariusza w MCP (`mcp-server/src/index.ts`, `getFullScenario`) nie pobierał kolumny `fee_basis` z `pool_tiers` w ogóle — więc nawet ustawiony poprawnie `per_member` był po stronie silnika `undefined` → płaski fee. Naprawiony w tym samym przebiegu (SELECT rozszerzony o `fee_basis, pool_size_basis`).
56
+
57
+
### Decyzja (amendment)
58
+
59
+
1.**`PoolTier.fee_basis` zyskuje trzecią wartość `'per_customer'`.** Opłata tieru = `monthly_fee × activeCustomers` tego miesiąca — ta sama zmienna co baza kohorty w projekcji (nie `aiUsers`). Modeluje subskrypcję płaconą przez każdego aktywnego klienta niezależnie od realnego użycia AI. `'per_member'` zostaje bez zmian semantyki (× `aiUsers`) — użyteczne tam, gdzie opłata faktycznie skaluje się z adopcją (np. dodatek per-seat aktywowany na żądanie).
60
+
2.**Nowe pole `PoolTier.pool_size_basis: 'absolute' | 'per_member'`** (domyślnie `'absolute'`, zachowuje dzisiejsze zachowanie). Przy `'per_member'` efektywna pula tego miesiąca = `credit_pool_size × aiUsers` — allowance skalowany per adopter, a nie stały worek. Konsumpcja/nadwyżka/breakage liczą się względem tej efektywnej puli (upper-band, zgodnie z istniejącą konwencją poola).
61
+
3.**Rozdzielenie „kto płaci" (fee_basis) od „ile jest wliczone" (pool_size_basis) jest celowe.** To dwa niezależne wymiary tej samej struktury cenowej — realny przypadek referencyjny łączy `fee_basis: 'per_customer'` (płaci każdy subskrybent) z `pool_size_basis: 'per_member'` (wliczone tylko dla tych, którzy faktycznie korzystają), ale kombinacja jest dowolna (np. B2B org-wide fee + per-seat allowance).
62
+
63
+
### Ekonomia referencyjna (Claude Pro + pula Fable, zweryfikowana silnikiem)
Test regresyjny: `src/lib/shared/financial-math.test.ts`, describe `'ADR 0012 amendment — two knobs'`, `'reproduces the Fable 5 reference economics …'`.
76
+
77
+
### Konsekwencje (amendment)
78
+
79
+
Pozytywne:
80
+
- Realny scenariusz Claude Pro + pula Fable koduje się dziś dokładnie (bez obejść, bez zniekształceń rzędu wielkości) — jedyne pozostałe uproszczenie to statyczne `seats` planu (nieużywane w tej ścieżce — `pool` nie potrzebuje planu do przychodu) i miesięczna granulacja silnika (tydzień → miesiąc, drobne).
81
+
-`fee_basis`/`pool_size_basis` to ortogonalne przełączniki — istniejące tiery (`flat`/`absolute`) i tiery z pierwszej Decyzji (`per_member`/`absolute`) działają bez zmian.
82
+
83
+
Negatywne / koszty:
84
+
-`pool_size_basis` to kolejna kolumna + migracja (Migracja 23), plus UI/MCP/eksport do rozszerzenia — czwarty punkt dotyku po `fee_basis` z Decyzji 1.
85
+
- Cztery kombinacje `fee_basis × pool_size_basis` (rosnące do sześciu przy przyszłych wartościach) zaczynają przypominać osobną strukturę cenową bardziej niż "pulę z dwoma trybami" — jeśli pojawi się piąty wymiar (np. sublimity per usługa, Q4 z sekcji głównej), warto rozważyć, czy `pool` nie powinien zostać rozbity na jawny obiekt konfiguracji zamiast rosnącej listy pól na `PoolTier`.
86
+
87
+
### Otwarte pytania (nie rozstrzygnięte tym amendmentem)
88
+
89
+
- Czy `pool_size_basis` powinien też przyjmować `'per_customer'` (allowance dla każdego subskrybenta, nie tylko adoptera)? Dziś niepotrzebne dla żadnego znanego przypadku — realna polityka Anthropic wlicza limit tylko aktywnym userom.
90
+
- Statyczne `seats` planu (luka #5 z analizy pierwotnej) — wciąż nierozwiązane, wciąż poza zakresem `pool`.
91
+
- Jawna cena nadwyżki (Q3 z sekcji głównej) — wciąż odłożona.
Copy file name to clipboardExpand all lines: CLAUDE.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -82,7 +82,7 @@ They share code through a **symlink**: `mcp-server/src/shared → ../../src/lib/
82
82
`calculateScenario` does **not** credit top-line revenue. The model (all in the shared module):
83
83
84
84
- **One revenue carrier (ADR 0001–0004).** Each scenario sets a `modeling_type` (`incremental` | `gtm` | `appraisal`) and a `revenue_carrier` (`cohort` | `plan` | `pack` | `feature`); `resolveCarrier` maps type → carrier (`incremental`→`cohort`, `gtm`→`plan`, `appraisal`→ the explicit carrier). **Exactly one carrier books revenue**, so cohort ARPU uplift, plan `seats × base_price`, and monetization overrides are never summed (the double-counting the old `revenue_source` `'both'` model caused). `calculateScenario` switches on the carrier — `cohort` = the incremental contribution-margin band; `plan` = plan subscription + monetization; `pack`/`feature` = monetization only. A `revenue_bridge` (`upsell_on_cohort` | `separate_market`) reconciles plan seats that coexist with a `cohort` carrier (`separate_market` = additive subscription; `upsell_on_cohort` = informational only, revenue still from cohort uplift). `validateRevenueIntegrity` returns `ok`/`warn`/`block` to stop double-counting at save time, surfaced via `scenario_results.revenue_integrity_status`/`revenue_integrity_message`. This replaces the deprecated `revenue_source` (`cohort` | `monetization` | `both`) summing model.
85
-
- **Per-archetype streams + credit pool (ADR 0009–0010).** `revenue_carrier` also accepts `'pool'`. Copilot (seat) and agent (interaction) are disjoint, summable streams: a monetized agent service (any `monetization_type !== 'none'`) books its price as revenue and excludes labor savings from cash (memo only, via `monthLaborSavingsCapacity`), avoiding price-vs-labor-savings double counting; an unmonetized agent still books labor savings as cash. `detectDriverProfile` classifies a scenario as `seat_only` | `interaction_only` | `mixed` (a revenue-booking seat-plan counts as the copilot signal even with no literal copilot service); `streamMargins` reports blended + per-stream gross margin against soft, scenario-overridable thresholds (`copilot_margin_threshold`/`agent_margin_threshold`, cascaded from `client_base` like `gross_margin`). `streamsDisjoint` is the test ADR 0001's incremental block defers to before hard-blocking monetization. The `'pool'` carrier (ADR 0010) bills one shared tier fee covering both streams via a `pool_tiers`/`pool_burn_rates` table; `validateRevenueIntegrity` hard-blocks mixing `monetization_type`s (or any `'outcome'` type) within one pool scenario. Credit value is `max(token-cost floor, capture × value_per_outcome)`; tier-fee + overage is attributed to copilot/agent proportional to lifetime EVC weight (`value_per_outcome × activity`), falling back to an even split when unset. Results surface as `CalculationResult.driverProfile`/`streamMargins`/`poolEconomics`, persisted in `scenario_results.driver_profile`/`stream_margins`/`pool_economics`.
85
+
- **Per-archetype streams + credit pool (ADR 0009–0010, amended by ADR 0012).** `revenue_carrier` also accepts `'pool'`. Copilot (seat) and agent (interaction) are disjoint, summable streams: a monetized agent service (any `monetization_type !== 'none'`) books its price as revenue and excludes labor savings from cash (memo only, via `monthLaborSavingsCapacity`), avoiding price-vs-labor-savings double counting; an unmonetized agent still books labor savings as cash. `detectDriverProfile` classifies a scenario as `seat_only` | `interaction_only` | `mixed` (a revenue-booking seat-plan counts as the copilot signal even with no literal copilot service); `streamMargins` reports blended + per-stream gross margin against soft, scenario-overridable thresholds (`copilot_margin_threshold`/`agent_margin_threshold`, cascaded from `client_base` like `gross_margin`). `streamsDisjoint` is the test ADR 0001's incremental block defers to before hard-blocking monetization. The `'pool'` carrier bills one shared tier fee covering both streams via a `pool_tiers`/`pool_burn_rates` table. Under ADR 0012, this is governed by two knobs: `fee_basis` (`flat` for flat monthly fee, `per_customer` for tier fee × active customers, `per_member` for tier fee × active AI users) and `pool_size_basis` (`absolute` for a static included-credits pool, `per_member` for included credits × active AI users). Credit value is `max(token-cost floor, capture × value_per_outcome)`; tier-fee + overage is attributed to copilot/agent proportional to lifetime EVC weight (`value_per_outcome × activity`), falling back to a profile-informed allocation (`profile_fallback`) or even split when EVC is 0. Results surface as `CalculationResult.driverProfile`/`streamMargins`/`poolEconomics`, persisted in `scenario_results.driver_profile`/`stream_margins`/`pool_economics`.
86
86
-**Contribution margin.** Each cohort carries a `gross_margin` (cascaded global → vertical → cohort, default `1.0`); incremental revenue is booked at margin, so cashflows reflect contribution, not gross revenue.
87
87
-**Upper/lower attribution band.** Three projections are built per cohort — baseline, full-adoption, and uplift-only (ARPU effect on a baseline customer-count path). The engine returns a band: **upper** = full retention + acquisition + price effect; **lower** = ARPU-uplift only. NPV, payback and the PI are each returned as `…Upper`/`…Lower`.
88
88
-**Adoption ramp.**`adoption_ramp_months` ramps effective adoption linearly from 0 to the target; implemented as a per-month blend `a(t)·fullAdopt + (1−a(t))·baseline` (the cohort model is linear in size, so `ramp=0` reproduces the old split). Late adopters inherit retention as if from month 0 — a documented approximation.
0 commit comments