- Date: 2026-03-19
- Last updated: 2026-03-23 (Phase 10 complete — P0–P4 (intelligence tools), Phase 10B P5–P7 (plugin sandboxing/signed manifests/auto-update), live pricing oracle (catalog-loader.ts, MCP_MODEL_CATALOG_URL → bundled fixture fallback), dev workflow script (scripts/dev.sh); 441 tests green; 244 MCP integration tests; integration adapters OpenOps/Infracost deferred to Phase 11 — see execution log; 2026-03-23 UX audit of ficecal-model-lens (localhost:4321 vs duksh.github.io): 10 first-time visitor experience gaps identified (G1–G10), prioritized resolution table and Phase 12 UX sprint scope added to §6A)
- Authoring basis: analysis of current live FiceCal (
http://duksh.github.io), current source repository runtime structure, andFiceCal-v2-ideacontracts/ADRs - Updated after additional comparison against:
- FinOps Foundation
FinOps Framework 2026: Executive Strategy, Technology Categories, and Converging Disciplines - FinOps Foundation
Introducing FOCUS 1.3: Contract Commitments, Split Cost Allocation, Dimensions for Recency & Completeness
- FinOps Foundation
- Status: active — Phase 9 complete ✅ · Phase 10 complete ✅ (billing.anomaly.detect + @ficecal/billing-ai-providers + finops.assessment.correlate + billing.routing.optimize; Phase 10B P5 sandboxing + P6 signed manifests + P7 auto-update; live pricing oracle; dev workflow; toolCount 11; transport v0.13.0; 441 tests) · Phase 11 complete ✅ (53-gap register: U1–U6, P1–P4, I1–I4, F1–F3/F7–F8, A2–A4/A6–A7, S1–S7, D1–D2/A1; 1,253 tests) · Phase 12 complete ✅ (8 new MCP tools, 23 total; Phase 12 tests; Phase 12 UX gaps closed) · UX audit 2026-03-23: 10 first-visit gaps on ficecal-model-lens (G1–G10) identified — Phase 13 UX sprint planned (see §6A)
| Date | Event |
|---|---|
| 2026-03-19 | Plan authored and reviewed |
| 2026-03-20 | GitOps foundation established: develop branch created off main in duksh/FiceCal; CI guardrails extended to all v2 branches |
| 2026-03-20 | duksh/models renamed to duksh/ficecal-model-lens; established as confirmed upstream for model catalog data |
| 2026-03-20 | PR #118 merged to develop: packages/schemas/model-catalog/ and packages/integrations/models-pricing/ delivered — implements Gaps 2, 3, 4 from section 4E |
| 2026-03-20 | Phase 0 exit artifacts created: docs/phase-0-baseline/framework-focus-coverage-baseline.md and docs/phase-0-baseline/parity-and-change-declaration.md; feature-catalog.json updated to v1.1.0 |
| 2026-03-20 | release/phase-0 branch opened; PR #119 raised to main — pending merge and v2.0.0-phase-0-exit tag |
| 2026-03-21 | Phase 1: economics-module compute kernel delivered — decimal.js-backed Decimal wrapper, toOutputString, normalizePeriod, FormulaRegistry, forex adapter (static + ECB interface); feature-catalog.json updated to v1.2.0 |
| 2026-03-21 | Phase 1 complete: v2.0.0-phase-1-exit tag cut on develop |
| 2026-03-21 | Phase 2: chart-presentation — canonical ChartPayload contract and builders (PR #25, baseline) |
| 2026-03-21 | Phase 2: health-score — deterministic weighted signal engine, worst-severity propagation, evaluatePricingFreshness / evaluateBudgetAdherence / evaluateModelTrust (PR #123, 22 tests) |
| 2026-03-21 | Phase 2: recommendation-module — 17 declarative rules, audience-aware (executive/operator/architect/viability) priority sort (PR #124, 31 tests) |
| 2026-03-21 | Phase 2: ai-token-economics — per_token/per_1k/per_1m/per_image/per_request/per_second dispatcher; Gap 1 closed (PR #125, 32 tests) |
| 2026-03-21 | Phase 2: feature-registry — Kahn topological sort, circular-dep detection, diamond-dep support (PR #127, 27 tests) — note: built during Phase 2 sprint; plan categorises as Phase 4/5 infrastructure; reconciliation recorded in Phase 3 section |
| 2026-03-21 | Phase 2: mcp-tooling — McpToolRegistry, economics.estimate.cost / health.score.query / economics.period.normalize tools (PR #128, 32 tests) — note: built ahead of Phase 5 plan schedule; see Phase 3 reconciliation note |
| 2026-03-21 | Phase 2: apps/web — Vite + React browser runtime, SharedContext, CostEstimator, HealthDashboard, ArchitectPanel (PR #129) — note: built ahead of Phase 4 plan schedule; see Phase 3 reconciliation note |
| 2026-03-21 | Phase 2: multi-tech-normalization — 10 TechCategory variants, costPerBasisUnit, efficiencyIndex, portfolio roll-up (PR #131, 16 tests) |
| 2026-03-21 | Phase 2: sla-slo-sli-economics — computeErrorBudget, computeDowntimeCost, computeReliabilityRoi; STANDARD_SLO_TIERS (PR #132, 18 tests) |
| 2026-03-21 | ADR — economics-module umbrella: @ficecal/economics-module established as the single-import surface for all economics engines. Implements EconomicsPlugin<TInput, TResult> extension interface; createDefaultRegistry() pre-wires 5 built-in domains; future verticals (cloud-economics, licensing, FinOps) self-register without touching existing consumers (PR #133, 23 tests) |
| 2026-03-21 | Phase 2: budgeting-forecasting — computeBudgetVariance, extrapolateTrend (OLS linear + moving-average), projectBudget (compound growth) (PR #134, 27 tests) |
| 2026-03-21 | Phase 2: reference-evidence — EVIDENCE_CATALOG (8 entries: FOCUS 1.3, FinOps Framework 2026, Google SRE, OLS regression, compound growth, weighted health score), queryEvidence() (PR #135, 34 tests) |
| 2026-03-21 | Phase 2: demo-scenarios — 6 canonical scenarios with live engine assertions: AI model cost, 99.9% error budget, e-commerce outage, 4-nines ROI, multi-cloud normalisation, Q1 budget variance (PR #136, 26 tests) |
| 2026-03-21 | Phase 2: qa-module — 7 engine contracts, runContractCheck() with dot-path resolver, cross-module integration harness covering all 6 demo scenarios (PR #137, 29 tests) |
| 2026-03-21 | Phase 2 complete — v2.0.0-phase-2-exit tag cut on develop; 352 tests passing across 14 packages; Gaps 1 and 5 closed |
| 2026-03-21 | Phase 3: @ficecal/ui-foundation delivered — 7 modules (types, preferences, theme, intent-scope, i18n, keyboard, telemetry); 75/75 vitest tests; zero DOM dependencies; all browser APIs injectable (PR #138) |
| 2026-03-21 | Phase 3: apps/web wired to ui-foundation — ThemeToggle (light/dark/system cycle), IntentScopeBar (intent/scope/mode selects + back + affinity hint), useUiFoundation() hook, i18n.t() throughout App.tsx (PR #139) |
| 2026-03-21 | Phase 3: feature-catalog.json bumped to v1.5.0 — ui-foundation entry active; web.dependsOn updated |
| 2026-03-21 | Phase 3 complete — v2.0.0-phase-3-exit tag cut on develop; 75 ui-foundation tests + clean typecheck; apps/web integration verified |
| 2026-03-21 | Phase 4: packages/contracts — zero-dependency cross-package boundary types: WorkspaceContext, IntentScopeSnapshot, EconomicsResultSummary, HealthSignalSummary, HealthScoreSummary, RecommendationSummary, TelemetryBase; feature-catalog.json bumped to v1.6.0 |
| 2026-03-21 | Phase 4: services/mcp scaffold — Phase 5 Fastify + MCP SDK transport structure documented and deferred; service-mcp (scaffold) entry added to feature-catalog.json |
| 2026-03-21 | Phase 4: CODEOWNERS added — path-based ownership for all packages, apps, services, .github, docs/roadmap |
| 2026-03-21 | Phase 4: docs/playbooks/monorepo-cutover-runbook.md — cutover readiness checklist (all ✅), post-cutover directory layout, package boundary rules, contract drift detection, rollback procedure |
| 2026-03-21 | Phase 4: apps/web production wiring (PR #141) — single-page layout (all panels always visible), NavBar sticky + IntersectionObserver active tracking, ScenarioBar preset loading from @ficecal/demo-scenarios, CostEstimator real-time compute (no button click), CostChart D3 bar renderer (ADR-0001), HealthDashboard live signal derivation from AiCostResult, complete --fc-* CSS token system with [data-theme="light"] vars |
| 2026-03-21 | Phase 4 complete — v2.0.0-phase-4-exit tag cut on develop; tsc --noEmit clean; monorepo cutover formalized; apps/web fully wired to economics engine |
| 2026-03-21 | Phase 5: services/mcp Fastify HTTP transport implemented (ADR-0002) — buildApp() factory, GET /mcp/v1/health, GET /mcp/v1/capabilities, POST /mcp/v1/tools/:id/call; singleton McpToolRegistry pre-wired with economics.estimate.cost, economics.period.normalize, health.score.query; buildRequestContext() from HTTP headers; RFC 7807-style error envelope |
| 2026-03-21 | Phase 5: 28/28 vitest transport tests — health liveness, capabilities manifest, 5 cost tool variants, 3 period normalization tests, 6 health score query tests, 4 error paths, 2 context propagation tests |
| 2026-03-21 | Monorepo: pinned TypeScript ~5.4.5 via pnpm.overrides to prevent TS 5.9 decimal.js NodeNext regression; fixed mcp-tooling health-score-query audiences type cast |
| 2026-03-21 | Phase 5 complete — v2.0.0-phase-5-exit tag cut on develop; 28/28 tests passing; tsc --noEmit clean |
| 2026-03-21 | Strategic pivot confirmed during Phase 6 planning — "WordPress of FinOps" direction adopted; plugin-first extensible architecture chosen over monolithic integration module; all Phase 6 integration work (OpenOps, Infracost, FOCUS normalization) deferred to Phase 8 to establish the plugin foundation first |
| 2026-03-21 | Phase 6: packages/plugin-api delivered — zero-dependency FicecalPlugin interface, PluginHost (feature-flag guard + contribution routing), ThemeRegistry (plugin-contributed visual themes), BillingRegistry (fixture + adapter registries), PluginRegistrationError with typed error codes; 25/25 tests |
| 2026-03-21 | Phase 6: billing fixture plugins — 4 deterministic provider plugins (AWS/GCP/Azure/OpenAI) each contributing BillingFixtureContribution + BillingAdapterContribution via PluginHost; fixture JSON files in packages/schemas/fixtures/ sourced from real Cost Explorer / GCP Billing Export / Azure Cost Management / OpenAI usage export formats |
| 2026-03-21 | Phase 6: billing MCP tools — billing.estimate.actual and billing.compare.period registered in MCP transport; setBillingRegistry() wires PluginHost.billing into tool handlers; 24/24 billing transport tests |
| 2026-03-21 | Phase 6: theme plugins — lightThemeContribution, darkThemeContribution, highContrastThemeContribution, oceanBlueThemeContribution defined in packages/ui-foundation/src/theme-plugins.ts; BUILT_IN_THEMES array exported; tokens sourced from THEME_TOKENS for single source of truth |
| 2026-03-21 | Phase 6: gap analysis against "WordPress of FinOps" target produced 9 identified gaps (see section 4G) — plugin marketplace, isolation/sandbox, multi-tenancy, hook/filter system, signed contracts, admin UI, update pipeline, developer SDK; ThemeRegistry → ThemeManager wiring (resolved in Phase 7 P0) |
| 2026-03-21 | Phase 6 complete — v2.0.0-phase-6-exit tag cut on develop; 77/77 tests passing (25 plugin-api + 52 mcp-service); tsc --noEmit clean across all packages |
| 2026-03-21 | Phase 7 P0: ThemeTokenSource interface added to @ficecal/ui-foundation — structural bridge from ThemeManager to ThemeRegistry (zero new package dep); ThemeManager extended with setCustomTheme(), clearCustomTheme(), getActiveThemeId(), listThemes(); custom theme id persisted at ficecal:theme:custom:v1 |
| 2026-03-21 | Phase 7 P0: useUiFoundation.ts wires PluginHost singleton with @ficecal/built-in-themes plugin (all 4 themes); passes pluginHost.themes as ThemeTokenSource to ThemeManager; pluginHost exposed through UiFoundation interface |
| 2026-03-21 | Phase 7 P0: ThemePicker.tsx delivered — full popover panel showing all plugin-contributed themes with swatch + displayName + description; setCustomTheme() / clearCustomTheme() wired; keyboard accessible (Escape + outside-click); 100+ CSS lines in styles.css |
| 2026-03-21 | Phase 7 P0: NavBar.tsx updated — ThemeToggle (3-state cycle) replaced by ThemePicker (full plugin-aware theme picker); @ficecal/plugin-api added to apps/web runtime dependencies |
| 2026-03-21 | Phase 7 P0: 13 new ThemeManager tests added to packages/ui-foundation/tests/ui-foundation.test.ts covering setCustomTheme, clearCustomTheme, getActiveThemeId, listThemes, ThemeTokenSource fallback, persistence across instances; total: 163 tests passing (86 ui-foundation + 25 plugin-api + 52 mcp-service) |
| 2026-03-21 | Phase 7 P1: AdminPanel.tsx Sections 1–3 delivered in apps/web — registered plugins list (name/version/stability/namespace), theme picker (all ThemeRegistry entries with active indicator + apply), billing provider status (BillingRegistry.readyProviders with fixture/adapter readiness dots). @ficecal/plugin-api added to apps/web runtime dependencies. Admin CSS tokens added to styles.css |
| 2026-03-21 | Phase 7 P2: Live billing toggle wired — ingestMode: "live" path added to AWS billing adapter; routes.ts returns 501 LIVE_BILLING_NOT_IMPLEMENTED with upgrade instructions until Phase 9 real SDK integration; routes.ts version bumped 0.6.0 → 0.8.0, phase: 6 → 8 |
| 2026-03-21 | Phase 7 partial complete — ThemeRegistry ✅, AdminPanel (Sections 1–3) ✅, live billing stub ✅. HookRegistry (addFilter/addAction) and WorkspaceRegistry carried forward to Phase 9 as P0/P1 |
| 2026-03-21 | Phase 8 P0: packages/schemas created — NormalizedCostRecord v2 (SCHEMA_VERSION = "2.0.0"); ~35 new optional fields covering ~63/77 FOCUS 1.3 columns (~82%); 7 new enum types (ChargeCategory, ChargeClass, ChargeFrequency, PricingCategory, CommitmentDiscountCategory, CommitmentDiscountStatus, PublisherCategory); FOCUS_V1_3_GAP_COLUMNS const documents 13 deferred columns; deriveTagKeys() and upgradeToV2() migration helpers; 77 vitest tests |
| 2026-03-21 | Phase 8 P1: packages/plugin-registry-client delivered — RegistryClient class with browse(), find(), listTags(), verifyBundle() (SHA-256 via Web Crypto API), checkReadiness(); in-memory caching; zero-dependency; RegistryFetchError and BundleVerificationError typed error classes; 63 vitest tests |
| 2026-03-21 | Phase 8 P2: packages/create-ficecal-plugin delivered — npx create-ficecal-plugin scaffold CLI; pure template functions (buildScaffoldFiles()); supports billing / theme / mcp / full plugin types; scaffolds package.json, tsconfig.json, README.md, src/index.ts, contribution file, test harness; 59 vitest tests |
| 2026-03-21 | Phase 8 P3: billing.commitment.status MCP tool delivered — all 7 FOCUS 1.3 CommitmentDiscount columns; built-in deterministic fixtures: AWS (3 records: 2 Savings Plans + 1 RI), GCP (2 CUDs), Azure (1 RI); filterStatus + filterType query params; CommitmentSummary with utilisationRate, totalWastedSpend, totalNetSavings; toolCount in transport → 6; 33 vitest tests |
| 2026-03-21 | Phase 8 P4: FinOps Framework 2026 assessment types added to @ficecal/contracts — FinOpsCapabilityDomain (6 domains incl. new ai-ml-cost-management), FinOpsMaturityLevel (crawl/walk/run), FinOpsCapabilityAssessment, FinOpsFrameworkAssessment (overall score, topRecommendations, overallMaturityLevel), FinOpsBenchmarkComparison (peerGroup, leaderDomains, laggingDomains), AiMlCostAssessment (tokenAttributionEnabled, gpuCommitmentUtilisationRate, costPerMillionTokens) |
| 2026-03-21 | Phase 8 P5: AdminPanel.tsx Section 4 — Registry Browser delivered; lazy-load with "Load registry" button; tag filter + search input; plugin cards with readiness dots, tag chips (clickable filter), install readiness issues, homepage links, published date; @ficecal/plugin-registry-client added to apps/web dependencies; registry CSS tokens added to styles.css |
| 2026-03-21 | Phase 8 partial complete — P0–P5 done (schemas ✅, registry-client ✅, create-plugin ✅, commitment MCP tool ✅, contracts types ✅, AdminPanel Section 4 ✅). Deferred to Phase 9: 8B integration adapters, duksh/ficecal-plugin-registry repo creation, billing.chargeback.allocate tool, live billing SDK |
| 2026-03-22 | Plan document updated — execution log brought current for Phase 7 P1/P2, Phase 8 P0–P5; FOCUS 1.3 coverage matrix updated 15%→82%; Framework 2026 matrix updated (FinOps Assessment: none→low); Phase 7 exit criteria updated; Phase 8 completed deliverables table added; Phase 9 section restructured with carryover items |
| 2026-03-22 | Phase 9 P0 (HookRegistry) confirmed complete — 44 vitest tests; priority-ordered filter/action chains; billing.estimate.actual.result production hook; lifecycle actions; registeredFilters/Actions introspection. Already wired in PluginHost as host.hooks |
| 2026-03-22 | Phase 9 P2 (WorkspaceRegistry) confirmed complete — 23 vitest tests; disablePluginForWorkspace, enablePluginForWorkspace, listPluginsForWorkspace, listThemesForWorkspace, listAdaptersForWorkspace; workspace.plugin.disabled/enabled hooks |
| 2026-03-22 | Phase 9 P1: duksh/ficecal-plugin-registry repo created — plugins/index.json (version/updatedAt/plugins shape per isRegistryIndex() validator); 2 seed entries (high-contrast + ocean-blue themes); JSON Schema v7; .github/workflows/validate-plugin.yml (schema, HTTPS, sha256, unique IDs, semver gates); CONTRIBUTING.md; README. DEFAULT_REGISTRY_INDEX_URL updated to point to plugins/index.json path |
| 2026-03-22 | Phase 9 P4: billing.chargeback.allocate MCP tool delivered — FOCUS 1.3 Allocation columns (AllocatedCost, AllocatedMethodID, AllocatedMethodDetails, AllocatedResourceID, AllocatedResourceName, AllocatedTags); even/proportional/tag-based allocation methods; AWS (2 resources: k8s-cluster $4800 + NAT $380), GCP (GKE $5200), Azure (AKS $3900) fixtures; rounding correction on last consumer; toolCount → 7; transport v0.9.0 / phase 9; 32 vitest tests. Total monorepo: 978 tests passing |
| 2026-03-22 | Phase 9 P3: Live AWS billing delivered — aws-billing-plugin.ts v2.0.0; real GetCostAndUsageCommand call via @aws-sdk/client-cost-explorer; MONTHLY granularity; UnblendedCost metric; GROUP_BY SERVICE dimension; mapResultsToLineItems() → BillingPeriodSummary; dynamic SDK import (zero cost in deterministic mode); 501 stub fully retired; billing test updated to accept [200, 500, 501] for CI without credentials |
| 2026-03-22 | Phase 9 proper #5: @ficecal/finops-assessment delivered — computeAssessment() engine; 6 domain scorers (scoreUnderstandCloudUsageCost, scoreQuantifyBusinessValue, scoreOptimizeCloudUsageCost, scoreManageFinOpsPractice, scoreCloudSustainability, scoreAiMlCostManagement); 21 boolean signal flags across 6 AssessmentSignals domain groups; modal maturity tie-break-to-lower; top-3 cross-domain recommendations ordered by lowest-scoring domain; 58 vitest tests |
| 2026-03-22 | Phase 9 proper #5 (cont.): finops.assessment.run MCP tool registered in transport — finops namespace; stability: beta; flat-signal input maps to all 6 AssessmentSignals groups; FinOpsFrameworkAssessment output aligned to @ficecal/contracts boundary types; toolCount → 8; transport v0.10.0; 36 vitest integration tests. Total monorepo: 962 tests passing |
| 2026-03-22 | Phase 10 P0: billing.anomaly.detect MCP tool delivered — threshold-based spike detection over NormalizedCostRecord[]; two-period comparison (current vs baseline); groups by serviceName, computes relative delta; flags services exceeding thresholdPercent (default 50%); severity: warning >50%, critical >100%; ranked by deltaAmount DESC; projectedMonthlyOverage on partial-month comparisons; multi-provider support (providers[] input); composite ingestMode (deterministic/live/mixed); BillingPeriodSummary and NormalizedCostRecord[] both handled at input; toolCount → 9; transport v0.12.0 / phase 10; 28 vitest integration tests. Total monorepo: 356 tests passing |
| 2026-03-22 | Phase 10 strategy confirmed — intelligence layer before integration adapters: (1) billing.anomaly.detect MCP tool — threshold-based spike detection over NormalizedCostRecord[]; (2) finops.assessment.correlate — assessment × billing × model-routing correlation; (3) billing.routing.optimize foundation; (4) all-provider AI billing adapters (Anthropic, OpenAI, Gemini, Mistral, DeepSeek, Alibaba) using ficecal-model-lens as pricing oracle rather than per-adapter pricing logic. OpenOps/Infracost integration adapters explicitly deferred to Phase 11. |
| 2026-03-22 | ficecal-model-lens role expanded — confirmed as pricing oracle for all AI billing adapters, not just reference data for ai-token-economics. packages/integrations/models-pricing/ (duksh-models-adapter, ModelPricingReference) is the resolved token-cost layer; billing adapters only need provider usage API (token counts); cost = tokens × ModelPricingReference rates. Forex already solved via Phase 1 StaticForexAdapter. Model name normalization via cleanName + company fields. Evidence rule maintained: adapter outputs labeled dataCompleteness: "partial" per FOCUS 1.3. |
| 2026-03-22 | Phase 8B critical gap closed — billing MCP tools upgraded from BillingPeriodSummary (12 FOCUS cols) to NormalizedCostRecord[] v2 (FOCUS 1.3, ~82% coverage). billing.estimate.actual: lineItems: BillingLineItemOutput[] → records: NormalizedCostRecord[]; lineItemCount → recordCount; mapper billingPeriodSummaryToRecords() produces FOCUS fields (serviceName, skuId, chargeDescription, chargeCategory: "usage", chargeFrequency: "usage-based", amountType: "actual", billedCost, effectiveCost, pricingCategory: "standard", providerRole mapped per provider family, dataCompleteness: "partial"); Phase 10 NormalizedCostRecord[] pass-through branch added. billing.compare.period: ServiceDelta.service → ServiceDelta.serviceName (FOCUS ServiceName); focusSchemaVersion: "2.0.0" in output; internal aggregation uses FOCUS field extraction helpers. @ficecal/schemas added to mcp-tooling deps. Transport v0.10.0 → v0.11.0. 161/161 integration tests green |
| 2026-03-22 | Phase 10 P1+P2: @ficecal/billing-ai-providers delivered — AiProviderBillingAdapter interface; 6 provider adapters (Anthropic, OpenAI, Gemini, Mistral, DeepSeek, Alibaba) each with deterministic fixtures (17 model entries, date-stamped usage records); AI_PROVIDER_ADAPTERS registry map (keyed by providerId); lookupModelPricing() — 4-pass fuzzy matcher (exact modelId+company → exact modelId → cleanName⊆slug → slug⊆cleanName) with slugify() stripping date suffixes; normalizeUsageRecords() — produces NormalizedCostRecord[] with FOCUS 1.3 fields (pricingCategory: "standard", serviceCategory: "AI and Machine Learning", resourceType: "foundation-model", dataCompleteness: "partial"); cost formula: (tokens / 1_000_000) × ratePerMillion; cached input tokens supported via cachedInputTokenCost; CredentialsRequiredError typed error class; 102 vitest tests (21 model-lookup + 40 normalize + 41 adapters). Wired into services/mcp via createAiProviderBillingRegistry() (PHASE10_PRICING_CATALOG, 17 hardcoded entries) and createMergedBillingRegistry(cloudReg, aiReg) composition; @ficecal/billing-ai-providers + @ficecal/schemas added to both mcp-tooling and services/mcp deps |
| 2026-03-22 | Phase 10 P3: finops.assessment.correlate MCP tool delivered — correlates FinOps capability gaps with billing spend to produce ROI-ranked correlatedRecommendations[]; 7 correlation rules: ai-model-routing-gap (20% AI spend, medium), ai-token-attribution-gap (5% AI spend, low), ai-cost-alerts-gap (15% AI spend, low), cloud-anomaly-detection-gap (15% total spend, low), cloud-waste-remediation-gap (10% cloud spend, medium), cloud-rightsizing-gap (8% cloud spend, medium), no-showback-chargeback-gap (0% waste, high effort); ROI score = (estimatedSaving / effortMultiplier) / 10000 × 100 capped 1–100, sorted DESC; output: totalBillingSpend, aiProviderSpend, cloudProviderSpend, totalAddressableWaste, topAddressableGap, overallScore, overallMaturityLevel, correlationVersion: "1.0"; CorrelationBillingRegistry wired to merged cloud+AI registry; finops namespace, stability: beta; toolCount → 10; 29 vitest integration tests |
| 2026-03-22 | Phase 10 UI: IntelligencePanel delivered in apps/web — three-section panel surfacing all Phase 10A intelligence tools; Section 1 (AI Model Routing): billing.routing.optimize call, hero saving stat, opportunity list with source→alternative model substitution cards and saving % badges; Section 2 (Spend Anomaly Detection): billing.anomaly.detect call, overall severity display, anomaly list with δ%, projected overage, per-anomaly recommendation; Section 3 (Assessment × Billing Correlation): finops.assessment.correlate call, FinOps score + maturity level, totalAddressableWaste hero stat, ROI-ranked gap list with effort badges; all three tools called in parallel via native fetch() to MCP service (VITE_MCP_BASE_URL, default localhost:4001); independent loading/error states per section; baseline period auto-computed as prior calendar month; NavBar Intelligence link added; App.tsx phase tag + footer bumped to Phase 10; tsc --noEmit clean; 244 MCP integration tests still green |
| 2026-03-22 | §4B Framework 2026 coverage matrix updated — Anomaly Management: none→medium; FinOps Assessment: medium→good; AI Multi-provider comparison: good→strong; AI token tracking: medium→good; AI maturity: low→medium; interpretation note updated to reflect Phase 10A complete state and remaining gaps (Rate Optimization, Usage Optimization, Sustainability, live pricing oracle) |
| 2026-03-22 | Phase 10 P4: billing.routing.optimize MCP tool delivered — identifies AI model swap opportunities ranked by estimated monthly saving; ROUTING_CATALOG (17 entries, 4 tiers: reasoning/premium/standard/economy); TIER_DOWNGRADE map (premium→standard, standard→economy; reasoning and economy → no substitution); saving formula: monthlySpend × (1 − altWeightedRate/sourceWeightedRate) with 70/30 input/output token weight; top-3 alternatives per source model sorted by estimatedMonthlySaving DESC; output: opportunities[], totalEstimatedMonthlySaving (10dp decimal string), modelsAnalysed, opportunitiesFound, providersCovered, catalogVersion: "phase-10-hardcoded"; topN (default 5) + minMonthlySaving (default 0) filters; RoutingBillingRegistry wired to AI-only registry; billing namespace, stability: beta; toolCount → 11; transport v0.13.0; 26 vitest integration tests. Total MCP integration tests: 244. Total monorepo: Phase 10 A P0–P4 complete |
| 2026-03-22 | Phase 10B P5: PluginSandbox delivered in packages/plugin-api/src/sandbox.ts — Promise.race execution with configurable timeoutMs (default 5000ms) + maxCallsPerPlugin (default 0 = unlimited) guards; per-plugin call count tracking (getCallCount, resetCallCount, resetAllCallCounts); SandboxViolationError extends Error with pluginId + reason fields; timeout wraps non-violation errors; zero external dependencies; 25 vitest tests |
| 2026-03-22 | Phase 10B P6: Signed manifests delivered in packages/plugin-api/src/manifest.ts — FicecalPluginManifest interface (id, name, version, contributions[], stability, optional bundleUrl/sha256/signingKey/createdAt); ManifestValidationError with field + reason; validatePluginManifest(unknown): asserts is FicecalPluginManifest validates scoped id regex (@scope/name), semver, contributions enum, stability enum, https-only bundleUrl, 64-char hex sha256; verifyBundleHash() via globalThis.crypto.subtle.digest("SHA-256"); immutable lock file utilities (PluginLockFile, PluginLockEntry, createLockFile, upsertLockEntry, removeLockEntry); 28 vitest tests |
| 2026-03-22 | Phase 10B P7: Plugin auto-update delivered in packages/plugin-api/src/updater.ts — PluginUpdateChecker with RegistryClient dependency; single browse() call for all plugins; integer semver comparison (major.minor.patch, ignores pre-release); checkForUpdates(installed, options?) returns PluginUpdate[]; hasUpdate(pluginId, currentVersion, options?) for point checks; PluginUpdate: { id, currentVersion, availableVersion, bundleUrl, bundleSha256, releaseNotes? }; @ficecal/plugin-registry-client: workspace:* added to plugin-api deps; 20 vitest tests. plugin-api total: 165 tests. All three Phase 10B deliverables green |
| 2026-03-22 | Phase 10 live pricing oracle: PHASE10_PRICING_CATALOG hardcoded array removed from ai-providers-billing-plugin.ts and ROUTING_CATALOG made data-driven. services/mcp/fixtures/model-pricing-catalog.json (17 entries, all ModelPricingReference fields) created as bundled source. services/mcp/src/plugins/catalog-loader.ts — loadModelPricingCatalog(): tries MCP_MODEL_CATALOG_URL env (HTTP GET, 8s timeout, validates array shape) → falls back to bundled fixture (synchronous readFileSync). setAiProviderPricingCatalog() + _resetAiProviderPricingCatalog() added to ai-providers-billing-plugin. buildRoutingCatalogFromPricing(ModelPricingReference[]) → RoutingModelEntry[] + setRoutingCatalog() + _resetRoutingCatalog() added to billing-routing-optimize tool; MODEL_TIER_MAP seeded from ROUTING_CATALOG; COMPANY_TO_PROVIDER map handles 6 vendors. initializeCatalog(): Promise<void> added to registry.ts — called from buildApp() in server.ts before registerMcpRoutes() so catalogs are populated before registry is built. _resetRegistry() also resets catalog singletons. catalogVersion field widened from literal to string. 244 MCP integration tests green; no new typecheck errors |
| 2026-03-22 | Dev workflow script: scripts/dev.sh created — starts @ficecal/service-mcp (port 4001) and apps/web (port 4321) concurrently with color-coded prefixed output; VITE_MCP_BASE_URL auto-injected from MCP_PORT env; both processes killed on Ctrl-C / EXIT trap; bash 4+ required; pre-flight checks for pnpm + directory existence. Root package.json updated with dev / dev:full / dev:mcp / dev:web scripts. Phase 10 fully complete. Total: 441 tests (244 MCP + 165 plugin-api + 32 mcp-tooling) |
| 2026-03-23 | UX audit — ficecal-model-lens (duksh.github.io) first-time visitor experience: live site (localhost:4321 vs duksh.github.io) compared by FinOps Product Owner review; 10 first-visit gaps identified (G1–G10) spanning brand confusion, missing value proposition, data-without-insight pattern, empty-cell ambiguity, missing FinOps job-to-be-done framing, unsurfaced column definitions, no social proof/trust signals, invisible power features (SQL query builder), mobile breakage, and absence of use-case filter shortcuts. Prioritized resolution table (P1–P8) and Phase 13 UX sprint scope added to §6A. See §6A for full gap register and remediation plan. |
This plan treats FiceCal v2 as a contract-first modular evolution of the current live product, not as a blind rewrite.
The primary goal is to preserve the strengths of the current shipped experience:
- explainable FinOps decision support
- deterministic cloud economics modeling
- scenario-driven analysis
- chart-led interpretation
- progressive disclosure through feature controls and user depth modes
While systematically moving the product toward the v2 target state:
- stable module contracts
- explicit UI foundation ownership
- hardened economics engine
- extracted chart / health / recommendation modules
- service and integration expansion through controlled boundaries
- governance-backed release gates
This plan now also explicitly recognizes two new facts:
- current FiceCal v1 aligns more strongly with FinOps Framework 2026's executive-strategy and decision-support direction than with its full operating-model breadth
- current FiceCal v1 has only light conceptual overlap with FOCUS 1.3 and is not yet a FOCUS-native data ingestion, allocation, or conformance surface
Current live/runtime reality appears to be:
- a static-first analytical product centered on
index.html - a large but capable orchestration shell with substantial inline UI and domain glue
- runtime modularization already started via
src/core/andsrc/features/ - working feature catalog and runtime gate model
- active domain modules already visible in product direction:
- core economics
- multi-tech normalization
- AI token economics
- SLA/SLO/SLI economics
- agent orchestration
- demo scenarios
- strong documentation and architecture intent already captured in docs and ADRs
Main gap versus v2 target:
- the current app is modular in intention but not yet modular in authority
index.htmlstill acts as the integration center for too much UI and domain behavior- contracts exist in planning form, but are not yet the authoritative implementation boundaries
- service/integration ambitions outpace current runtime extraction maturity
Additional standards-alignment assessment:
- FinOps Framework 2026: FiceCal v1 partially covers executive strategy alignment, KPI-oriented decision support, and some architecture/optimization thinking, but does not yet cover the broader FinOps operating model, scopes framework, governance breadth, sustainability, or cross-category practice depth
- FOCUS 1.3: FiceCal v1 currently models commitment economics conceptually, but does not yet implement dedicated contract commitment datasets, split cost allocation semantics, allocation-method transparency, recency/completeness metadata, or service-provider vs host-provider data modeling
Implication:
- v2 should deliberately strengthen two separate alignment tracks:
- Framework alignment through scopes, business-question framing, technology-category expansion, and strategic decision support
- FOCUS readiness through normalized cost data contracts, metadata, allocation semantics, and adapter-based ingestion
- Preserve behavioral parity before expanding scope.
- Establish the economics engine as the most trusted module first.
- Separate UI foundation concerns from business/domain concerns.
- Extract modules in dependency order, not according to novelty.
- Add service and provider integrations only after browser/runtime contracts are stable.
- Use release gates to protect trust, not just code quality.
- Keep compatibility aliases until migration evidence is complete.
- Treat Framework 2026 alignment and FOCUS readiness as explicit roadmap outcomes, not incidental side effects.
- Build business-question and scope awareness before deep provider-specific ingestion complexity.
- Make FOCUS support adapter-driven and schema-first rather than hardwired into UI behavior.
Run v2 in two synchronized tracks:
Focus:
- browser runtime stabilization
- modularization of current features
- UX/HCI hardening
- contract-aligned parity
Focus:
- MCP service layer
- integration-module implementation
- normalized cost data model for FOCUS-ready ingestion
- model catalog and pricing reference ingestion for AI economics
- OpenOps / Infracost adapters
- later direct billing adapters
- monorepo cutover when enough shared assets are real
Reason:
Trying to perform full UI/platform rewrite, modular extraction, service introduction, and billing integration in one stream would create unnecessary coordination and regression risk.
FiceCal v2 should align first with the areas where the current product already has strategic momentum:
- executive strategy alignment
- KPI-led decision support
- architecting and workload-placement tradeoff framing
- usage optimization guidance
FiceCal v2 should add structured support for:
- explicit FinOps scopes
- broader technology category coverage
- stronger governance and policy interpretation surfaces
- future sustainability readiness, but not at the expense of core economics modularization
FiceCal v2 should not claim FOCUS alignment until it supports, through explicit contracts where relevant:
- contract commitment dataset handling
- split shared-cost allocation representation
- allocation-method transparency
- recency and completeness metadata
- service-provider vs host-provider distinction
Recommendation:
- treat FOCUS support as a data-model and integration capability, not as a mere UI labeling exercise
Last updated: 2026-03-21 against FinOps Framework 2026 (finops.org/insights/2026-finops-framework/) and FOCUS 1.3 ratified 2025-12-04.
The 2026 Framework reorganises capabilities across 4 domains with 22 named capabilities (up from 18), introduces the AI technology category page, and refocuses from "cloud" to "technology". Key 2026 changes: new Executive Strategy Alignment capability; 6 capabilities renamed for technology-agnosticism; Scopes now business-question-driven, not analyst-driven; Intersecting Disciplines (ITAM, SAM, ITFM, Sustainability) as a formal capability.
| Capability | v2 status | Phase covered | FiceCal evidence |
|---|---|---|---|
| Data Ingestion | low | Phase 8 | Billing fixture plugins deliver deterministic data; no FOCUS-normalized ingestion pipeline; no multi-source aggregation |
| Allocation | none | Phase 8 | NormalizedCostRecord contract defines allocation fields (allocationScope, allocationMethod) but the module is not built; BillingLineItem has tags only |
| Reporting & Analytics | medium | Phase 4 (partial) → Phase 7 | apps/web health dashboard + D3 cost charts exist; no FOCUS-native views; no persona-segmented report distribution |
| Anomaly Management | medium | Phase 10 ✅ | billing.anomaly.detect MCP tool: threshold-based spike detection over NormalizedCostRecord[]; two-period comparison; severity (warning >50%, critical >100%); projectedMonthlyOverage; composite ingestMode; 28 integration tests. UI surface: IntelligencePanel anomaly section in apps/web |
| Capability | v2 status | Phase covered | FiceCal evidence |
|---|---|---|---|
| Planning & Estimating | good | Phase 2 ✅ | demo-scenarios (6 canonical scenarios); budgeting-forecasting variance; ai-token-economics estimation |
| Forecasting | good | Phase 2 ✅ | budgeting-forecasting: OLS linear trend, moving average, compound growth projection |
| Budgeting | good | Phase 2 ✅ | budgeting-forecasting: computeBudgetVariance, projected budget overage/underage |
| KPIs & Benchmarking | medium | Phase 2–3 ✅ | health-score weighted signals; recommendation-module priority sort; no technology-category-specific KPI library yet; no FOCUS-derived benchmarks |
| Unit Economics | strong | Phase 2 ✅ | ai-token-economics (6 pricing units); multi-tech-normalization (10 tech categories, efficiencyIndex); sla-slo-sli-economics (error budget, downtime cost, reliability ROI); core-economics normalizePeriod |
| Capability | v2 status | Phase covered | FiceCal evidence |
|---|---|---|---|
| Architecting & Workload Placement | low | Phase 4 (skeletal) → Phase 8 | ArchitectPanel exists in apps/web but is not connected to real model-comparison computation; no multi-category workload placement framing |
| Rate Optimization | none | Phase 9+ | No rate optimization, commitment discount modelling, or reserved-instance analysis module |
| Usage Optimization | none | Phase 9+ | No usage optimization, rightsizing, or idle-resource detection |
| Sustainability | none | Phase 9+ | No carbon, embodied emissions, or operational carbon module |
| Licensing & SaaS | none | Phase 9+ | No SaaS spend tracking, seat utilization, or software license optimization |
| Capability | v2 status | Phase covered | FiceCal evidence |
|---|---|---|---|
| FinOps Practice Operations | low | Phase 7 | Plugin admin panel (Phase 7) is the first operations surface; no maturity tracking, team structure, or practice KPI model |
| Governance, Policy & Risk | low | Phase 7 | Phase 7 release gates (fixture parity, invariant tests, alignment evidence) are CI governance; no user-facing policy or risk interpretation surface |
| FinOps Assessment | good | Phase 8 ✅ (types) + Phase 9 ✅ (engine + MCP tool) + Phase 10 ✅ (billing correlation + UI) | @ficecal/finops-assessment scoring engine: 6 domain scorers, modal maturity tie-break, 58 tests; finops.assessment.run MCP tool (36 tests); finops.assessment.correlate MCP tool: 7 correlation rules, ROI-ranked correlatedRecommendations, totalAddressableWaste from real spend, 29 tests; IntelligencePanel assessment×billing correlation section in apps/web |
| Automation, Tools & Services | low | Phase 5 ✅ (partial) | MCP service layer + 5 tools is the automation surface; billing plugins are the "services" layer; breadth is narrow |
| FinOps Education & Enablement | none | Phase 9+ | No glossary, learning paths, or enablement content surface |
| Invoicing & Chargeback | none | Phase 8 | Not started; requires FOCUS-aligned billing data (Phase 8 dependency) |
| Intersecting Disciplines | none | Phase 9+ | No ITAM, SAM, ITFM, or security integration surface |
| Executive Strategy Alignment (new 2026) | low | Phase 7–8 | executive intent + executive-strategy scope exist in ui-foundation; no actual strategic decision support surface, multi-year investment model, or leadership KPI narrative module |
FiceCal v2 is strongest here relative to the 2026 Framework due to the depth of ai-token-economics and the model catalog integration.
| AI Consideration | v2 status | FiceCal evidence |
|---|---|---|
| Cost per inference / per token | strong ✅ | ai-token-economics computes cost for 6 pricing units including per_1m_tokens, per_image; economics.estimate.cost MCP tool exposes this to AI agents |
| Multi-provider model comparison | strong ✅ | ModelPricingReference + duksh-models-adapter + ficecal-model-lens upstream; 6 AI provider billing adapters (Anthropic/OpenAI/Gemini/Mistral/DeepSeek/Alibaba) in @ficecal/billing-ai-providers; billing.routing.optimize identifies cheaper equivalents across all providers |
| Token consumption tracking | good | economics.estimate.cost MCP tool; billing.estimate.actual per-provider NormalizedCostRecord[]; @ficecal/billing-ai-providers normalizes token usage → FOCUS 1.3 records for all 6 AI providers; session-level tracking deferred |
| GPU cost modelling | none | No infrastructure-level GPU cost module |
| Training vs inference cost separation | partial | Tags in BillingLineItem can distinguish workloads; billing.estimate.actual returns per-service breakdown; no first-class separation until NormalizedCostRecord v2 serviceSubcategory (Phase 8) |
| AI governance / quota management | none | No spend quota, throttling, or AI-specific governance module |
| Crawl/Walk/Run maturity for AI FinOps | medium | AiMlCostAssessment in @ficecal/contracts; finops.assessment.correlate surfaces AI-specific gaps (hasAiCostVisibility, hasTokenAttribution, hasModelCostOptimization, hasAiCostAlerts) with ROI-ranked recommendations; IntelligencePanel exposes maturity level + addressable waste in apps/web |
FOCUS 1.3 (ratified 2025-12-04) defines two datasets: Cost and Usage Dataset (77 columns) and the new Contract Commitment Dataset (13 columns — note: plan previously stated 11, corrected 2026-03-21). FiceCal's BillingPeriodSummary and BillingLineItem from Phase 6 are lightweight custom schemas that overlap with ~12 of 77 FOCUS columns.
Updated 2026-03-21 (Phase 8 P0): NormalizedCostRecord v2 ("2.0.0") delivered in packages/schemas. Coverage now ~82%. Remaining 13 columns deferred and documented in FOCUS_V1_3_GAP_COLUMNS.
| Category | Columns (77 total) | FiceCal v2 equivalent | Coverage |
|---|---|---|---|
| Account (6) | BillingAccountID, BillingAccountName, BillingAccountType, SubAccountID, SubAccountName, SubAccountType | All 6 added in v2 (billingAccountId/Name/Type, subAccountId/Name/Type) |
6/6 ✅ |
| Allocation (5) | AllocatedMethodDetails, AllocatedMethodID, AllocatedResourceID, AllocatedResourceName, AllocatedTags | allocatedCost + allocatedMethodID added; AllocatedResourceID/Name/Tags deferred |
1/5 |
| Billing (9) | BilledCost, BillingCurrency, ConsumedQuantity, ConsumedUnit, ContractedCost, ContractedUnitPrice, EffectiveCost, ListCost, ListUnitPrice | All 9 added in v2 (7 FOCUS cost columns + billedUnitPrice; consumedQuantity/Unit mapped) |
9/9 ✅ |
| Capacity Reservation (2) | CapacityReservationID, CapacityReservationStatus | deferred — in FOCUS_V1_3_GAP_COLUMNS |
0/2 |
| Charge (4) | ChargeCategory, ChargeClass, ChargeDescription, ChargeFrequency | All 4 added in v2 (enums + chargeDescription) |
4/4 ✅ |
| Charge Origination (6) | HostProviderName (1.3), InvoiceID, InvoiceIssuer, ProviderName, PublisherName, ServiceProviderName (1.3) | provider, serviceProviderName, hostProviderName, publisherName added; invoiceId/Issuer deferred |
4/6 |
| Commitment Discount (7) | CommitmentDiscountCategory, CommitmentDiscountID, CommitmentDiscountName, CommitmentDiscountQuantity, CommitmentDiscountStatus, CommitmentDiscountType, CommitmentDiscountUnit | All 7 added in v2 + billing.commitment.status MCP tool covers all 7 |
7/7 ✅ |
| Contract (13) (1.3 new dataset) | ContractApplied, ContractCommitmentCategory … ContractPeriodStart | deferred — in FOCUS_V1_3_GAP_COLUMNS |
0/13 |
| Location (3) | AvailabilityZone, RegionID, RegionName | All 3 added in v2 | 3/3 ✅ |
| Pricing (7) | PricingCategory, PricingCurrency, PricingCurrencyContractedUnitPrice, PricingCurrencyEffectiveCost, PricingCurrencyListUnitPrice, PricingQuantity, PricingUnit | pricingCategory, pricingCurrency, pricingQuantity, pricingUnit, pricingUnitPrice added; 2 PricingCurrency variants deferred |
5/7 |
| Resource (3) + Tags | ResourceID, ResourceName, ResourceType, Tags | resourceType + tagKeys added in v2; resourceId/Name already present |
4/4 ✅ |
| Service (3) | ServiceCategory, ServiceName, ServiceSubcategory | All 3 added in v2 | 3/3 ✅ |
| SKU (4) | SKUID, SKUMeter, SKUPriceDetails, SKUPriceID | deferred — in FOCUS_V1_3_GAP_COLUMNS |
0/4 |
| Timeframe (4) | BillingPeriodEnd, BillingPeriodStart, ChargePeriodEnd, ChargePeriodStart | All 4 present (v1 carried forward; ChargePeriod fields added in v2) | 4/4 ✅ |
Current FOCUS coverage: ~51 of 77 columns (~82%) — credible alignment claim for Cost and Usage Dataset. Contract Dataset (13 cols) and SKU (4 cols) remain deferred.
| FOCUS 1.3 addition | What it enables | Phase 8 target |
|---|---|---|
| Contract Commitment Dataset (13 columns) | Query all active commitments; reserved instance exposure; RI coverage reporting | NormalizedCostRecord.contract.* schema + fixture |
| Allocation columns (5) | Understand how providers distributed shared costs; chargeback transparency | allocationMethodID, allocationMethodDetails, allocatedResourceID/Name/Tags |
| ServiceProviderName / HostProviderName | Distinguish who sells vs. who hosts (critical for marketplace + multi-tier architectures) | providerRole enum in NormalizedCostRecord |
| Data recency / completeness | Timestamp metadata + final vs. provisional data flags; stale-data warnings | dataRecencyTimestamp, dataCompleteness (already in NormalizedCostRecord contract) |
| EffectiveCost vs BilledCost vs ListCost | Distinguish actual spend from committed/contracted rates from list prices | Three separate cost fields in NormalizedCostRecord |
| ChargeCategory / ChargeClass | Separate usage charges from tax, adjustment, refund, purchase | amountType expansion in NormalizedCostRecord |
Interpretation updated 2026-03-22 (Phase 10A complete):
- FiceCal v2 is the strongest FinOps tool for AI cost intelligence in the framework's AI technology category — 6-provider AI billing adapters (
@ficecal/billing-ai-providers),billing.routing.optimizemodel substitution,finops.assessment.correlateAI gap ROI ranking, andIntelligencePanelUI surface all now ship together - FiceCal v2 can make a credible FOCUS alignment claim:
NormalizedCostRecordv2 covers ~82% of Cost and Usage Dataset columns. Contract Dataset (13 cols) and SKU (4 cols) remain deferred inFOCUS_V1_3_GAP_COLUMNS - Anomaly Management is now
mediumcoverage —billing.anomaly.detect+IntelligencePanelanomaly section provide active FinOps alerting - FinOps Assessment is now
good—finops.assessment.correlatecloses the gap between maturity scores and dollar impact; practitioners can seetotalAddressableWastefrom their actual billing data commitment-managementandshared-cost-allocationscopes are both backed:billing.commitment.status(7 FOCUS CommitmentDiscount cols) andbilling.chargeback.allocate(even/proportional/tag-based allocation) delivered in Phase 9- FiceCal v2's biggest remaining Framework 2026 gaps: Rate Optimization (no commitment discount modeling), Usage Optimization (no rightsizing/idle detection), Sustainability (no carbon module), live AI billing API calls (currently deterministic-only), and the pricing catalog being hardcoded rather than live from ficecal-model-lens
The first scope taxonomy should help FiceCal organize analysis around business questions rather than around raw feature lists.
- scopes should be understandable to executive, operator, and architect audiences
- scopes should map to decision questions, not implementation details
- scopes should be stable enough for telemetry, reporting, and recommendation framing
- scopes should allow future FOCUS-backed data enrichment without changing their user-facing meaning
| Scope key | Primary business question | Main audience | Typical outputs |
|---|---|---|---|
baseline-unit-economics |
what does this workload or service fundamentally cost and why | operator, architect | baseline cost, cost drivers, normalized unit view |
optimization-opportunities |
where is waste, inefficiency, or mis-sizing likely present | operator | savings signals, recommendation priority, efficiency health |
architecture-tradeoffs |
which design or hosting choice produces the better economic outcome | architect | scenario comparison, tradeoff narrative, break-even signals |
executive-strategy |
which decisions deserve leadership attention and investment prioritization | executive | KPI summary, risk summary, prioritization narrative |
commitment-management |
how should commitments be interpreted, compared, and governed | operator, executive | commitment exposure, utilization, coverage, risk |
shared-cost-allocation |
how should shared or indirect costs be assigned and explained | operator, executive | allocation breakdown, method transparency, fairness rationale |
- Phase 2 should operationalize:
baseline-unit-economicsoptimization-opportunitiesarchitecture-tradeoffsexecutive-strategy
Phase 6 should operationalize:deferred to Phase 8 (2026-03-21: Phase 6 pivoted to plugin architecture foundation; these scopes require FOCUS Allocation and Contract Commitment columns which are Phase 8 deliverables)commitment-management— requiresNormalizedCostRecordv2 Contract Commitment Dataset (Phase 8A) andbilling.commitment.queryMCP tool (Phase 8)shared-cost-allocation— requires FOCUS Allocation columns (Phase 8A) andbilling.chargeback.allocateMCP tool (Phase 8)
⚠️ UX note (2026-03-21): Bothcommitment-managementandshared-cost-allocationscopes are live inIntentScopeStatebut have zero backing computation, MCP tools, or UI content. Until Phase 8 delivers the required modules, these scope options should be guarded by a feature flag or displayed with a "coming soon" degradation state to prevent users from selecting empty scopes.
- Intent answers why the user came
- Scope answers which business question is active
- Mode answers how much detail is exposed
FiceCal v2 should treat FiceCal Model Lens (duksh/ficecal-model-lens) and Vantage-compatible model catalog data as a dedicated reference-data integration track for AI model economics.
FiceCal Model Lens is the renamed and rebranded version of duksh/models. It is a standalone Astro + React + Tailwind site with its own scraper pipeline and CI, acting as the authoritative upstream model catalog.
| Attribute | Value |
|---|---|
| Repo | duksh/ficecal-model-lens (formerly duksh/models) |
| Live site | modellens.ficecal.com (planned) |
| Status | Active — scrapers running for AWS Bedrock, GCP, Azure AI, OpenAI, Anthropic, Mistral, DeepSeek, Alibaba, IBM |
| Data output | public/data.json — scraped on a schedule, committed on change |
| Connection to FiceCal v2 | duksh-models-adapter in packages/integrations/models-pricing/ consumes data.json; no direct repo dependency |
| Monorepo cutover | Deferred to Phase 4; until then operates as a separate deployable |
Model Lens carries priceVerifiedAt timestamps on all hardcoded image prices, and the adapter translates priceSource into pricingSourceType — giving FiceCal v2 full pricing provenance from scrape time through to UI badge.
- provide model/vendor/region pricing reference data for
ai-token-economics - support architecture and optimization comparisons for AI workloads
- enrich recommendation and executive strategy outputs with market-reference model choices
- support scenario design without being mistaken for actual billed cost evidence
- act as the pricing oracle for all live AI billing adapters — billing adapters fetch token counts from provider usage APIs; cost = tokens ×
ModelPricingReferencerates from model-lens; this eliminates per-adapter pricing logic entirely - enable model routing optimization — when combined with actual
NormalizedCostRecordspend data, model-lens pricing enablesbilling.routing.optimizeto identify cheaper equivalent models; this is the capability that makes FiceCal's AI cost management unique vs generic FinOps tools - cover all major AI providers — Anthropic, OpenAI, GCP (Gemini), Azure AI, Mistral, DeepSeek, Alibaba (Qwen), IBM (Watsonx), plus LiteLLM/OpenRouter aggregators; multi-currency handled via Phase 1
StaticForexAdapter
This pattern governs how all AI provider billing adapters consume model-lens pricing:
ficecal-model-lens data.json
→ duksh-models-adapter (packages/integrations/models-pricing/)
→ ModelPricingReference { inputTokenCost, outputTokenCost, cachedInputCost, pricingSourceType, sourceVersion }
→ AiProviderBillingAdapter.fetchUsage() returns token counts only
→ normalize.ts: tokens × ModelPricingReference rates → NormalizedCostRecord v2
→ dataCompleteness: "partial" (token-level detail; no region/SKU from usage APIs)
Guardrail: billing adapter outputs must never set dataCompleteness: "complete" — usage APIs do not provide full FOCUS column coverage. Native provider adapters (Phase 11) using billing export APIs may qualify for "complete".
ModelPricingReferenceis reference catalog dataNormalizedCostRecordis cost and usage fact data- FiceCal may combine these in scenario and recommendation layers, but must never silently present them as the same class of evidence
- prefer
duksh/ficecal-model-lensas the curated upstream when available - treat Vantage-compatible data structures as the interoperability target for adapter design
- snapshot imported model catalog data into versioned fixtures before broad product reliance
integration-moduleshould own ingestion, refresh, caching, and fixture generationai-token-economicsshould consume normalized model pricing referencesarchitecture-tradeoffsshould use model/vendor/region comparisons for decision framingrecommendation-moduleshould consume derived comparison outputs, not raw source tables
- outputs using model catalog data must be labeled as reference, scenario, or estimated unless corroborated by actual cost records
This section addresses five open gaps identified during cross-referencing of the duksh/ficecal-model-lens upstream against the ModelPricingReference contract.
| Gap | Status |
|---|---|
| Gap 1 — Image pricing unit mismatch | Closed ✅ — per_image dispatch branch implemented in ai-token-economics (PR #125); computeImageCost handles imageOutputCost path; exhaustive discriminated-union switch enforced |
| Gap 2 — Source attribution | Implemented — pricingSourceType mapping delivered in PR #118 (packages/schemas/model-catalog/, packages/integrations/models-pricing/src/transform.ts) |
| Gap 3 — Snapshot versioning | Implemented — computeSourceVersion() delivered in PR #118 (packages/integrations/models-pricing/src/snapshot.ts) |
| Gap 4 — Approved benchmark list | Implemented — APPROVED_BENCHMARKS typed const delivered in PR #118 (packages/schemas/model-catalog/index.ts) |
| Gap 5 — Forex source dependency | Closed ✅ — ForexRateProvider interface, StaticForexAdapter, and normalizePeriod delivered in @ficecal/core-economics (Phase 1); ECB live feed adapter deferred to integration phase (Phase 6) — static fixture adapter is CI/offline default |
Problem: ModelPricingReference and ai-token-economics are designed around token-denominated pricing. Image generation models (Imagen 3, DALL-E, Titan Image) are priced per image, not per token. The original pricingUnit field did not define per_image semantics, and there was no field for image output cost.
Implemented (PR #118 + upstream duksh/ficecal-model-lens):
pricingUnitnow explicitly supportsper_imageas a valid enum value alongside1K_tokensand1M_tokens— defined inpackages/schemas/model-catalog/index.tsimageOutputCosthas been added toModelPricingReferenceas a required field whenpricingUnitisper_imagepriceVerifiedAthas been added to the upstream (ficecal-model-lens) image vendor records and flows through the adapter; staleness badge implemented in the Model Lens UI (30-day threshold: amber → red)- Token cost fields (
inputTokenCost,outputTokenCost, etc.) are explicitly absent on image records — enforced by adapter transform
Remaining for Phase 2:
ai-token-economicsdispatch branch (pricingUnit === "per_image"→imageOutputCostpath) not yet implemented- Decision confirmed: use
pricingUnitdispatch insideai-token-economics, not a separate module (see resolution approach below)
Module impact:
ai-token-economicsmust not attempt to apply token-based unit economics to a record withpricingUnit: per_image- a dedicated
ai-image-economicspath should be defined withinai-token-economicsor as a sibling module that handles image generation cost modeling (cost = quantity × imageOutputCost) architecture-tradeoffsandrecommendation-modulemust treat image and token costs as incommensurable unless explicitly normalized by the user
Extend ai-token-economics with a pricingUnit dispatch branch at the top of the cost computation function. Do not create a separate module at this stage — the two cost shapes are simple enough that a branch is the right boundary:
computeModelCost(record, quantity):
if record.pricingUnit === "per_image":
return quantity × record.imageOutputCost // images × cost/image
else:
return (quantity / unitDenominator) × tokenCost // tokens ÷ 1M × cost/1M
Extraction trigger: only promote image logic to a standalone ai-image-economics module if resolution tiers, batch pricing, or other image-specific dimensions emerge that would make the branch materially more complex than the token path. Until then, module proliferation is the greater risk.
Problem: duksh/ficecal-model-lens carries a priceSource field per vendor entry (scraped, hardcoded, litellm) but ModelPricingReference had no equivalent field. Without this, FiceCal cannot surface pricing reliability to users or treat hardcoded Imagen prices differently from LiteLLM-scraped GPT-4o prices in outputs.
Delivered: pricingSourceType has been added to ModelPricingReference as a required enum field in packages/schemas/model-catalog/index.ts. The adapter in packages/integrations/models-pricing/src/transform.ts maps upstream priceSource → pricingSourceType at ingestion. The Model Lens UI already surfaces price badges: "↻ Live pricing" (dynamic), "⚠ Manually maintained" (hardcoded fresh), "⚠ Unverified (N days old)" (hardcoded stale).
Resolution: pricingSourceType has been added to ModelPricingReference as a required enum field:
| Value | Meaning |
|---|---|
dynamic |
price was scraped from a live or frequently-updated external catalog (e.g. LiteLLM) at adapter ingestion time |
hardcoded |
price is manually maintained in source code; no programmatic upstream; staleness must be tracked by effectiveAt |
verified |
price was confirmed against a vendor's authoritative source (pricing API, official pricing page) at a known point in time |
Consumer guidance:
ai-token-economicsandai-image-economicsoutputs must surfacepricingSourceTypein their output evidence payload- the UI must display a distinct visual indicator for
hardcodedprices (e.g. "⚠ Manually maintained") versusdynamicprices (e.g. "↻ Live source") recommendation-modulemust not rank or compare ahardcodedprice against adynamicprice without surfacing the reliability difference to the user
Map duksh/ficecal-model-lens priceSource field to pricingSourceType at the adapter boundary:
duksh/ficecal-model-lens priceSource |
ModelPricingReference pricingSourceType |
|---|---|
litellm |
dynamic |
scraped |
dynamic |
hardcoded |
hardcoded |
UI badge rules:
dynamic→ "↻ Live source" indicator (subtle, informational)hardcoded→ "⚠ Manually maintained" indicator (amber, draws attention to potential staleness)verified→ "✓ Verified [date]" indicator (green, sourced from a vendor's authoritative endpoint)
recommendation-module rule: when a multi-model comparison includes entries of mixed pricingSourceType, the evidence payload must include a reliability caveat and surface it to the user. Silent ranking of mixed-source prices is not permitted.
Delivered: computeSourceVersion(), parseSourceVersion(), and sourceVersionAgeInDays() implemented in packages/integrations/models-pricing/src/snapshot.ts. Format is sha256(data.json)[0:12]@YYYY-MM-DD. Fixture tests confirm determinism and correct age calculation.
Problem: duksh/ficecal-model-lens produces a single flat data.json with no built-in version identifier. The ModelPricingReference contract requires sourceVersion, but the upstream provides no canonical way to generate one.
Resolution: the duksh-models-adapter must generate its own sourceVersion on each ingestion using the following convention:
sourceVersion = sha256(data.json contents)[0:12] + "@" + ingestedAt[0:10]
Example: a3f9b12cd401@2026-03-20
Rationale:
- the content hash detects actual data changes even if the file modification date is unchanged
- the ingestion date suffix makes human inspection practical
- this is stable enough for fixture determinism without requiring
duksh/ficecal-model-lensto adopt versioning itself
Additional guidance:
- if
duksh/ficecal-model-lensis later extended with a manifest version orscrapedAtmetadata field, the adapter should prefer that over the hash-based convention - the adapter must log and expose
sourceVersionin everyModelPricingReferencerecord it emits - fixture snapshots must be named by
sourceVersionto enable deterministic test replay
Versioning is entirely inside the adapter — zero changes required to duksh/ficecal-model-lens:
sourceVersion = sha256(data.json contents)[0:12] + "@" + ingestedAt[0:10]
// example: a3f9b12cd401@2026-03-20
Content-addressed skip rule: if the hash component of sourceVersion matches the last successfully ingested snapshot, skip re-snapshotting. This gives free incremental caching without any state management beyond storing the last known hash.
Fixture naming: snapshot-{sourceVersion}.json stored under packages/model-catalog-contracts/fixtures/. Test suites reference fixtures by sourceVersion string, never by relative path alone, so replaying any historical snapshot is unambiguous.
Delivered: APPROVED_BENCHMARKS typed const and ApprovedBenchmarkKey type implemented in packages/schemas/model-catalog/index.ts. The adapter strips any key not in the list at ingestion time and counts stripped keys in strippedBenchmarkCount. Fixture tests confirm enforcement. The list matches the resolution approach exactly.
Problem: benchmarkScores in ModelPricingReference is an open object map. Without a curated approved list, the adapter will pass through whatever benchmarks duksh/ficecal-model-lens includes on any given day, making recommendation-module outputs non-deterministic across snapshot versions when benchmark availability varies.
Resolution: the following benchmark keys are approved for inclusion in benchmarkScores at Phase 1:
| Key | Description |
|---|---|
swe_bench_verified |
SWE-bench Verified score (software engineering task resolution) |
mmlu |
MMLU aggregate score (multitask language understanding) |
humaneval |
HumanEval pass@1 (code generation) |
gpqa_diamond |
GPQA Diamond score (graduate-level scientific reasoning) |
math_500 |
MATH-500 score (competition mathematics) |
aime_2024 |
AIME 2024 score (advanced math olympiad) |
Rules:
- the
duksh-models-adaptermust strip any benchmark key not in this approved list before emitting aModelPricingReferencerecord - the approved list is a versioned artifact owned by
model-catalog-contracts; additions require an explicit ADR or plan amendment - benchmark scores must carry no implied weight in
recommendation-moduleranking without explicit user opt-in
The approved list lives as a typed const in model-catalog-contracts:
// packages/model-catalog-contracts/src/approvedBenchmarks.ts
export const APPROVED_BENCHMARKS = [
"swe_bench_verified",
"mmlu",
"humaneval",
"gpqa_diamond",
"math_500",
"aime_2024",
] as const
export type ApprovedBenchmarkKey = typeof APPROVED_BENCHMARKS[number]
Adapter strip-at-ingestion pattern:
const filtered = Object.fromEntries(
Object.entries(raw.benchmarkScores ?? {})
.filter(([key]) => APPROVED_BENCHMARKS.includes(key))
)
Governance rule: any addition to APPROVED_BENCHMARKS requires a PR to that file and a note in the plan amendment log. The file is the gate — convention alone is not sufficient.
Problem: FiceCal v1 already performs currency conversion (evidenced by the forex.json dependency). Model prices from duksh/ficecal-model-lens are USD-only. Phase 1 adds currency normalization to economics-module, but the plan does not define where the forex rates come from.
Resolution: the following forex source hierarchy is recommended:
- Primary: a scheduled-fetch from the European Central Bank (ECB) daily reference rates XML feed (
https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml) — free, authoritative, no API key required - Fallback: a versioned static
forex-rates.jsonfixture bundled with the repo, manually updated when the primary feed is unavailable - Adapter boundary: forex rates must be injected into
economics-moduleas a named dependency, never imported directly inside domain logic — this keeps the module deterministic and testable with fixture rates
Staleness rule: if the fetched ECB rates are older than 3 calendar days relative to the current calculation date, the UI must surface a stale-forex warning equivalent in severity to the stale-reference model pricing warning.
Scope: this applies to all currency-normalized outputs, including model pricing reference costs, unit economics outputs, and any scenario that presents multi-currency comparisons.
Define a ForexRateProvider interface as the injection contract:
interface ForexRateProvider {
getRates(baseCurrency: string, asOf: Date): Promise<ForexRates>
ageInDays(): number
}
Two implementations:
EcbForexAdapter— fetches the ECB daily reference rates XML feed (https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml), parses EUR-base rates, derives any cross-rate on demand. No API key required.StaticForexAdapter— reads a versionedforex-rates.jsonfixture from the repo. Used in all tests and as the CI/offline fallback.
Injection pattern — economics-module never imports forex directly:
const forex = await EcbForexAdapter.load()
if (forex.ageInDays() > 3) emitWarning("stale-forex")
const module = new EconomicsModule({ forex })
This keeps economics-module fully deterministic in tests (swap in StaticForexAdapter with fixture rates) and decouples the live feed from domain logic. The forex-rates.json fallback must be updated manually whenever the ECB feed is unavailable for an extended period; this update should be part of the same workflow as the npm run init scraper cycle.
| Step | Gap | Status | Rationale |
|---|---|---|---|
| 1 | Gap 3 — Snapshot versioning | ✅ Done (PR #118) | Zero-risk, self-contained adapter utility; unblocks fixture generation for all subsequent work |
| 2 | Gap 4 — Approved benchmark list | ✅ Done (PR #118) | Zero-risk typed constant; must exist before any adapter emits benchmarkScores |
| 3 | Gap 2 — Source attribution | ✅ Done (PR #118) | Requires Gap 3 (snapshots) to be testable; adapter mapping is low-complexity |
| 4 | Gap 1 — Image pricing unit | ✅ Done (PR #125) | computeImageCost dispatch branch implemented inside ai-token-economics; exhaustive switch enforced |
| 5 | Gap 5 — Forex source | ✅ Done (Phase 1 core-economics) | ForexRateProvider interface + StaticForexAdapter delivered; ECB live adapter deferred to Phase 6 |
Added 2026-03-21 after Phase 6 plugin architecture decision.
FiceCal v2's long-term platform ambition is to become the WordPress of FinOps: a product where the core ships a trustworthy analytical foundation and the ecosystem builds the long tail of providers, themes, integrations, and vertical-specific modules as plugins — without requiring changes to core.
WordPress's dominance came from five structural advantages: an ecosystem lock-in loop, zero-friction install model, a marketplace, a theme/plugin runtime, and a reliable update path. The Phase 6 plugin-api establishes the first structural primitive. The gaps below must be closed systematically across Phases 7–9.
| Gap | Priority | Target Phase | Description |
|---|---|---|---|
| No hook/filter system | P0 | Phase 7 | Plugins can only add contribution points — they cannot transform outputs. add_action / add_filter equivalents needed. This is WordPress's actual moat. |
✅ Done (Phase 7 P0, 2026-03-21) — ThemeTokenSource interface bridges ThemeManager ↔ ThemeRegistry without a package dep; setCustomTheme() / clearCustomTheme() / listThemes() added; ThemePicker.tsx live in apps/web; NavBar updated; 163 tests passing |
|||
| No admin / configuration UI | P1 | Phase 7 | No surface for users to see installed plugins, switch themes, or check billing provider status. Without this, the plugin system is invisible. |
| No multi-tenancy / workspace isolation | P1 | Phase 7 | workspaceId exists in McpRequestContext but plugins, billing adapters, and theme preferences are global singletons. Required for hosted SaaS model. |
| No plugin marketplace / registry client | P2 | Phase 8 | Plugins are hard-coded imports in registry.ts. Community developers cannot publish without a code change. Resolved design: GitHub-based registry at duksh/ficecal-plugin-registry (PR-based submission, jsDelivr CDN, packages/plugin-registry-client fetches index.json). |
| No developer SDK / scaffolding | P2 | Phase 8 | No npx create-ficecal-plugin, no testing utilities for plugin authors, no ficecal-plugin.json standard. |
| No update / versioning pipeline | P2 | Phase 8 | Billing fixture data requires a full redeployment to update. No auto-update mechanism for plugins. |
| No plugin isolation / sandbox | P3 | Phase 9 | All plugins share the same JS process. A buggy community plugin can crash the MCP service or read cross-workspace billing data. |
| No signed / verified plugin contracts | P3 | Phase 9 | Any FicecalPlugin object can claim any ID. Community distribution requires code-signing, version pinning, and manifest verification. |
The two gaps that unlock the ecosystem flywheel fastest are:
- Hook/filter system — makes plugins composable (one plugin's output becomes another plugin's input) — Phase 7 P1, not yet started
- Live theme picker — visible proof to end users that the plugin architecture is real; lowest-friction community contribution path — ✅ Done (Phase 7 P0, 2026-03-21)
Hook/filter system is now the sole remaining flywheel-critical gap.
| WordPress concept | FiceCal equivalent | Status |
|---|---|---|
| Theme API | ThemeContribution + ThemeRegistry + ThemePicker |
Built + wired to UI (Phase 7 P0 ✅) — ThemeManager.setCustomTheme() routes through ThemeRegistry; ThemePicker.tsx lists all plugin-contributed themes with swatches |
Plugin API (FicecalPlugin) |
@ficecal/plugin-api |
Built (Phase 6) ✅ |
wp-admin |
Plugin/theme admin panel in apps/web |
Phase 7 |
add_action / add_filter |
HookRegistry in @ficecal/plugin-api |
Phase 7 |
wordpress.org/plugins |
duksh/ficecal-plugin-registry (GitHub) + plugin-registry-client |
Phase 8 (client ✅ done; registry repo ⬜ Phase 9) |
| Theme/plugin signing | Signed ficecal-plugin.json manifests |
Phase 9 |
| Multisite | WorkspaceRegistry multi-tenancy |
Phase 9 (carried from Phase 7) |
| Auto-updates | Plugin update pipeline | Phase 9 |
| Hook/filter system | HookRegistry addFilter / addAction |
Phase 9 P0 (carried from Phase 7) |
| Developer SDK | npx create-ficecal-plugin scaffold CLI |
Phase 8 ✅ done — 4 plugin types, 59 tests |
| Admin Browse Plugins tab | AdminPanel Section 4 — Registry Browser |
Phase 8 ✅ done — lazy-load, tag/search filters, readiness |
| SHA-256 bundle verification | Web Crypto API in plugin-registry-client |
Phase 8 ✅ done |
| FinOps Assessment types | @ficecal/contracts boundary interfaces |
Phase 8 ✅ done — 6 domains, 3 maturity levels |
| FinOps Assessment engine | @ficecal/finops-assessment + finops.assessment.run MCP tool |
Phase 9 ✅ done — 6 domain scorers; 58 engine tests + 36 MCP tests; toolCount → 8 |
| CommitmentDiscount MCP tool | billing.commitment.status — all 7 FOCUS columns |
Phase 8 ✅ done — AWS/GCP/Azure fixtures |
| Live AWS billing adapter | aws-billing-plugin.ts v2.0.0 — real Cost Explorer SDK |
Phase 9 ✅ done — 501 stub retired; dynamic SDK import |
| Billing MCP tools on NormalizedCostRecord v2 | billing.estimate.actual + billing.compare.period upgraded from BillingPeriodSummary |
Phase 9 ✅ done — FOCUS dead end resolved; transport v0.11.0 |
This section documents the actual branch and repo structure established on 2026-03-20.
| Repo | Purpose | Status |
|---|---|---|
duksh/FiceCal |
FiceCal v2 monorepo (pnpm workspaces) | Active — develop branch is the v2 integration base |
duksh/ficecal-model-lens |
FiceCal Model Lens — standalone AI model catalog site (formerly duksh/models) |
Active — separate repo until Phase 4 monorepo cutover |
main ← v1 production (protected; no v2 code ever lands here directly)
develop ← v2 integration base (all feature PRs target here)
feature/<name> ← individual features branched off develop
fix/<name> ← bug fixes branched off develop (or main for hotfixes)
release/phase-<N> ← phase release candidates; merged → main on sign-off
v2.0.0-phase-0-exit ← immutable snapshot on merge of release/phase-0 → main
v2.0.0-phase-1-exit
...
v2.0.0-rc.1 ← release candidate after Phase 7
v2.0.0 ← FiceCal v2 GA
| Branch | Jobs |
|---|---|
main |
v1 lint, typecheck, build, deploy to production |
develop |
lint, typecheck, build, unit tests, deploy to v2-staging |
feature/* |
lint, typecheck, build, unit tests |
fix/* |
lint, typecheck, build, unit tests |
release/phase-N |
full test suite + economics parity checks + benchmark whitelist enforcement |
| Environment | Source | URL (planned) |
|---|---|---|
| v1 production | main |
ficecal.com |
| v2 staging | develop |
v2-staging.ficecal.com |
| Model Lens | main of duksh/ficecal-model-lens |
modellens.ficecal.com |
- Secret scanning: enabled
- CodeQL static analysis: enabled
- Dependabot security alerts: enabled
- GitHub Dependency Graph: enabled (required for
dependency-review-action)
- Set branch protection rules on
mainanddevelop(require PR + CI green + 1 approval; no force push) - Set
developas the default PR base branch in GitHub repo settings - Open
release/phase-0branch when Phase 0 parity deliverables are complete
Status: complete — All exit criteria met. PR #119 open to merge release/phase-0 → main. Tag v2.0.0-phase-0-exit pending on merge.
developbranch created offmaininduksh/FiceCal- CI guardrails workflow (
.github/workflows/ci-guardrails.yml) extended to trigger ondevelop,feature/**,fix/**,release/** duksh/modelsrenamed toduksh/ficecal-model-lenson GitHub; local remote updated- First feature branch
feature/model-catalog-contractscreated, reviewed, and merged todevelopas PR #118 - Delivered:
packages/schemas/model-catalog/index.ts,packages/integrations/models-pricing/(adapter, transform, snapshot, tests, fixtures, contract doc) - GitHub Advanced Security enabled: secret scanning, CodeQL, Dependabot, Dependency Graph
Define the current live product as the v2 parity baseline before deep architectural changes.
- canonical fixture payloads for current calculator states
- baseline scenario fixtures for current demos
- output snapshots for current core outputs
- chart rendering parity baselines for representative states
- UX task baselines for:
- baseline calculation
- demo scenario load
- feature toggle usage
- chart interaction
- output interpretation panel usage
- docs/glossary navigation
- baseline classification of current coverage against:
- Framework 2026 strategic capabilities
- FOCUS 1.3 data-model capabilities
- documented list of intentional v2 behavior changes vs parity-preserved behaviors
- known-good baseline is documented and reproducible
- parity acceptance rules exist for core outputs and key flows
- strategic-alignment baseline is documented so future roadmap claims can be measured honestly
Promote the current core-economics responsibility into the v2 economics-module with explicit contracts and deterministic guarantees.
- introduce
economics-moduleas canonical contract boundary - keep compatibility mapping from
core-economics - implement input schema validation
- implement output schema validation
- add deterministic numeric handling
- add period granularity support:
- monthly
- quarterly
- annual
- add currency normalization support
- define the first normalized cost-record contract that future integrations can map into
- define the first compatibility contract for business-question framing and future FinOps scopes
- define bounded precision policy
- create formula traceability registry
- implement invariant/property tests
decimal.jszodand/orajvvitestdate-fnsfor period helpers where needed
This should be the first integration-facing canonical payload that non-browser sources can map into before FiceCal-specific interpretation is applied.
| Field | Type | Required | Purpose |
|---|---|---|---|
recordId |
string | yes | stable unique identifier for the normalized record |
sourceSystem |
string | yes | origin system such as OpenOps, Infracost, AWS CUR-derived pipeline, or manual import |
provider |
string | yes | provider or platform family associated with the cost |
providerAccountId |
string | no | billing or tenant account identifier |
billingPeriodStart |
string | yes | ISO datetime for billing period start |
billingPeriodEnd |
string | yes | ISO datetime for billing period end |
chargePeriodStart |
string | no | ISO datetime for usage or charge start |
chargePeriodEnd |
string | no | ISO datetime for usage or charge end |
currency |
string | yes | ISO currency code |
amount |
string | yes | decimal-safe monetary amount represented as string |
amountType |
string enum | yes | one of actual, amortized, blended, list, allocated |
serviceCategory |
string | no | normalized service family or technology category |
serviceName |
string | no | source service label |
resourceId |
string | no | resource or asset identifier when available |
resourceName |
string | no | display label for the billed object |
usageQuantity |
string | no | decimal-safe usage quantity |
usageUnit |
string | no | normalized usage unit |
commitmentType |
string | no | reserved instance, savings plan, committed use, contract, or equivalent |
commitmentReference |
string | no | identifier linking the record to a commitment object or contract |
allocationScope |
string | no | indicates whether cost is direct, shared, or redistributed |
allocationMethod |
string | no | explicit allocation rule such as even, weighted, proportional, manual |
allocationSource |
string | no | source record or rule set used for allocation |
consumerEntityId |
string | no | team, product, application, or cost-center consumer |
ownerEntityId |
string | no | owning team or platform entity |
providerRole |
string enum | no | one of service-provider, host-provider, direct-provider, unknown |
region |
string | no | region or geography label |
tags |
object | no | normalized low-cardinality tag map |
dimensions |
object | no | validated extension bucket for source-specific attributes |
dataCompleteness |
string enum | no | one of complete, partial, unknown |
dataRecencyTimestamp |
string | no | ISO datetime indicating freshness evaluation point |
ingestedAt |
string | yes | ISO datetime when FiceCal ingested the record |
schemaVersion |
string | yes | normalized contract version |
- monetary and usage numerics should remain decimal-safe strings until parsed by canonical math utilities
amountTypemust prevent silent mixing of actual, amortized, or allocated viewsallocationMethod,allocationScope,dataCompleteness, andproviderRoleare critical for future FOCUS-oriented evidence claimsdimensionsmay extend the payload, but must not replace named canonical fields where a cross-adapter concept already exists
- reject records where
billingPeriodStartis afterbillingPeriodEnd - reject records missing
recordId,sourceSystem,provider,currency,amount,amountType,ingestedAt, orschemaVersion - reject invalid enum values for
amountType,providerRole, anddataCompleteness - require
allocationMethodwhenallocationScopeindicates redistributed or shared cost - require
commitmentReferencewhencommitmentTypeis present and the upstream source provides one
This contract should represent AI model catalog and pricing reference data used for scenario building, architecture comparisons, and recommendation enrichment.
| Field | Type | Required | Purpose |
|---|---|---|---|
modelRefId |
string | yes | stable unique identifier for the model reference entry |
sourceCatalog |
string | yes | source catalog such as ai/models, Vantage-compatible snapshot, or curated internal registry |
sourceVersion |
string | yes | source dataset or snapshot version |
modelId |
string | yes | upstream model identifier |
modelName |
string | yes | normalized display name |
company |
string | no | originating model company |
vendorId |
string | yes | serving vendor or platform identifier |
vendorName |
string | yes | serving vendor display name |
regionCode |
string | no | vendor region code when region-specific pricing applies |
currency |
string | yes | ISO currency code for pricing fields |
inputTokenCost |
string | no | decimal-safe string cost per input token unit |
outputTokenCost |
string | no | decimal-safe string cost per output token unit |
cachedInputTokenCost |
string | no | decimal-safe string cached-input cost |
cachedOutputTokenCost |
string | no | decimal-safe string cached-output cost |
latencyMs |
number | no | representative latency measurement |
tokensPerSecond |
number | no | throughput estimate when available |
lowCapacity |
boolean | no | indicator of constrained serving availability |
reasoningCapable |
boolean | no | whether the model is explicitly reasoning-oriented |
selfHostable |
boolean | no | whether the model is self-hostable |
tokenizer |
string | no | tokenizer identifier |
tokenizerUrl |
string | no | tokenizer reference URL |
benchmarkScores |
object | no | curated benchmark map restricted to the approved list defined in section 4E |
pricingUnit |
string | yes | pricing denominator: 1K_tokens, 1M_tokens, or per_image |
imageOutputCost |
string | no | decimal-safe cost per generated image; required when pricingUnit is per_image |
pricingSourceType |
string enum | yes | one of dynamic, hardcoded, verified; signals reliability of the pricing data |
effectiveAt |
string | no | ISO datetime for price effectiveness when known |
ingestedAt |
string | yes | ISO datetime when FiceCal ingested the record |
schemaVersion |
string | yes | contract version |
- reject records missing
modelRefId,sourceCatalog,sourceVersion,modelId,modelName,vendorId,vendorName,currency,pricingUnit,pricingSourceType,ingestedAt, orschemaVersion - when
pricingUnitisper_image: requireimageOutputCost; rejectinputTokenCost,outputTokenCost,cachedInputTokenCost, andcachedOutputTokenCostas inapplicable - when
pricingUnitis token-denominated: require at least one ofinputTokenCost,outputTokenCost,cachedInputTokenCost, orcachedOutputTokenCost - reject negative pricing, latency, or throughput values
- require
regionCodewhen the source record is region-qualified - treat benchmark values as optional reference signals, not canonical determinants of recommendation quality
- reject
benchmarkScoreskeys that are not in the approved benchmark list defined in section 4E - reject
pricingSourceTypevalues outside the approved enum
The recommended architecture is a one-way normalization pipeline from external model catalog data into FiceCal contracts.
duksh-models-adapter- reads curated upstream model catalog snapshots from
duksh/ficecal-model-lens(data.json) or API responses - validates raw source shape
- maps source tables into FiceCal canonical contracts
- reads curated upstream model catalog snapshots from
model-catalog-contracts- owns
ModelPricingReferenceand related schema validation
- owns
ai-token-economics- consumes canonical model pricing references for unit-cost and scenario computation
recommendation-module- consumes derived comparison outputs, not raw adapter payloads
architecture-tradeoffs- consumes normalized vendor/model/region comparison surfaces
integration-module- orchestrates refresh, fixture generation, caching, and failure handling
models-> model identity, company, reasoning flags, self-hostability, benchmark metadatavendors-> vendor identity and documentation metadatamodels_vendors-> vendor availability, latency, throughput, low-capacity markersmodels_vendors_regions-> regional token pricing referencemodels_tokenizers-> tokenizer metadatavendor_regions-> region descriptors and grouping metadata
- ingest
duksh/ficecal-model-lensdata.jsonsnapshot or compatible snapshot data - validate raw source schema at adapter boundaries
- normalize into
ModelPricingReferencerecords - snapshot normalized fixtures for deterministic testing
- feed derived pricing views into
ai-token-economics,architecture-tradeoffs, andrecommendation-module - expose optional MCP capabilities only after the normalized views are stable
- never couple UI components directly to upstream
duksh/ficecal-model-lensdata structures - never merge
ModelPricingReferenceandNormalizedCostRecordinto one ambiguous payload - always label outputs that use model catalog prices as reference, scenario, or estimated views rather than actual billed cost unless corroborated by cost records
FiceCal must define explicit degradation behavior for cases where model catalog data is unavailable, incomplete, or stale. Acceptable failure posture rules:
Missing model entry
- if a model referenced in a scenario or calculation has no matching
ModelPricingReferencerecord, the affected output must surface a visibleunresolved-model-referencewarning - the economics engine must not silently substitute zero, null, or a fallback price from a different model
- the user must be informed which model is unresolved and why the output is incomplete or suspended
Stale pricing data
ModelPricingReferencerecords carryingestedAtand optionallyeffectiveAt- if the age of the snapshot (relative to
ingestedAt) exceeds a configurable staleness threshold (recommended default: 7 days), affected outputs must be labeledstale-referencerather thanreference - the UI must surface a staleness indicator at the output level, not only at the data-source level
- scenario and recommendation outputs must not suppress the staleness label even if the computed numbers are otherwise valid
Partial catalog availability
- if a subset of models in a multi-model comparison scenario resolves successfully but others do not, FiceCal must not silently drop the unresolved entries from the comparison
- the comparison surface must show the unresolved entries as explicitly absent with a reason, so users understand the comparison is incomplete
Adapter ingestion failure
- if the
duksh-models-adapterfails to ingest or validate a new snapshot, FiceCal must fall back to the last known good versioned fixture - the fallback state must be surfaced to the user with the fixture version and ingestion timestamp
- integration-module must log the failure reason and expose it through the release health surface
Exit criteria addition for Phase 1
- failure posture rules are encoded as integration tests covering: missing model, stale snapshot, partial catalog, and adapter ingestion failure cases
- no consumer module (
ai-token-economics,architecture-tradeoffs,recommendation-module) passes a silent or zero-price result when model pricing is unresolved
- fixture parity against current live outputs passes
- invariant suite passes at 100%
- schema compatibility rules exist for dependent modules
- economics compute budgets meet contract thresholds
- economics payloads can act as a stable substrate for future scope-aware and FOCUS-aware modules
Status: complete ✅ — All exit criteria met. v2.0.0-phase-2-exit tag cut on develop (2026-03-21). 352 tests passing across 14 packages.
| Package | PR | Tests | Notes |
|---|---|---|---|
@ficecal/chart-presentation |
baseline | 20 | ChartPayload contract, builders, validators |
@ficecal/health-score |
#123 | 22 | Weighted signal engine, worst-severity propagation, 3 signal evaluators |
@ficecal/recommendation-module |
#124 | 31 | 17 declarative rules, 4 audience personas, priority sort |
@ficecal/ai-token-economics |
#125 | 32 | 6 pricing units incl. per_image (Gap 1 closed) |
@ficecal/feature-registry |
#127 | 27 | Kahn topological sort, circular-dep detection (see Phase 3 reconciliation note) |
@ficecal/mcp-tooling |
#128 | 32 | McpToolRegistry, 3 economics tools (see Phase 3 reconciliation note) |
apps/web |
#129 | — | Vite + React browser runtime, 3 modes (see Phase 3 reconciliation note) |
@ficecal/multi-tech-normalization |
#131 | 16 | 10 TechCategory variants, efficiencyIndex |
@ficecal/sla-slo-sli-economics |
#132 | 18 | Error budget, downtime cost, reliability ROI |
@ficecal/economics-module |
#133 | 23 | Umbrella registry + plugin interface — see ADR below |
@ficecal/budgeting-forecasting |
#134 | 27 | Budget variance, OLS trend, compound growth projection |
@ficecal/reference-evidence |
#135 | 34 | 8-entry evidence catalog, queryEvidence() |
@ficecal/demo-scenarios |
#136 | 26 | 6 canonical scenarios with live engine assertions |
@ficecal/qa-module |
#137 | 29 | 7 engine contracts, cross-module integration harness |
Decision: introduce @ficecal/economics-module as the single-import surface for all FiceCal v2 economics engines.
Context: by the end of Phase 2 the monorepo contained 4 separate economics packages (ai-token-economics, sla-slo-sli-economics, multi-tech-normalization, core-economics). Consumers faced multiple import paths. Future verticals (cloud-economics, licensing, FinOps) needed a stable extension point without breaking existing consumers.
Resolution:
EconomicsPlugin<TInput, TResult>interface: the contract every economics engine satisfies to self-register (domain,version,description,compute())EconomicsRegistry: domain-keyed plugin store withregister/unregister,lookup/require,compute()dispatcher,manifest()introspectioncreateDefaultRegistry(): pre-wires 5 built-in domains —ai.token,reliability.error-budget,reliability.downtime-cost,reliability.roi,tech.normalization- Re-exports all sub-module public APIs as a single convenience import surface
Extension rule: future economics modules register a plugin implementation; no core changes required. The domain key namespace convention is <vertical>.<function> (e.g. cloud.egress, licensing.saas).
Extract and harden the modules that already drive visible product value.
chart-presentationhealth-score-modulerecommendation-modulemulti-tech-normalizationai-token-economicssla-slo-sli-economicsdemo-scenariosreference-evidence-modulebudgeting-forecasting-moduleqa-modulehardening around the full chain
- chart, health, and recommendations represent the clearest visible decision-support value
- optional economics domains should consume canonical module outputs rather than ad hoc page state
- scenario and evidence layers should rely on stable payload contracts
- this phase should begin translating current calculator behavior into clearer Framework 2026-aligned business-question surfaces without yet requiring live external billing integrations
- each module has an explicit consumer boundary
- no major domain logic remains trapped as hidden inline-only page behavior if it belongs to a module
- chart payloads are normalized and contract-tested
- health and recommendation outputs are deterministic for identical inputs
- recommendation and evidence surfaces can explain outputs in terms that are understandable to executive, operator, and architecture audiences
Status: complete ✅ — All deliverables merged to develop; v2.0.0-phase-3-exit tag cut 2026-03-21.
During the Phase 2 sprint, three packages were built that the original plan assigns to later phases:
| Package | Built as | Plan phase | Decision |
|---|---|---|---|
@ficecal/feature-registry |
Phase 2 sprint (PR #127) | Phase 4 (monorepo infrastructure) | Keep as-is. Dependency ordering demanded it exist before mcp-tooling; low coupling, no UI involvement. |
@ficecal/mcp-tooling |
Phase 2 sprint (PR #128) | Phase 5 (MCP service layer) | Keep as-is. Browser-side tool registry only; no Fastify/transport wiring yet. Phase 5 adds the actual service layer. |
apps/web |
Phase 2 sprint (PR #129) | Phase 4 (monorepo cutover + web app) | Keep as-is. Bootstrapped Vite + React harness; not a production app yet. Phase 4 will migrate it to the full monorepo structure. |
Impact on Phase 3: none. The plan's Phase 3 scope (ui-foundation) is unchanged — these pre-built packages do not implement or substitute any of the Phase 3 deliverables below. Phase 3 work targets ui-foundation exclusively.
Impact on Phase 4: apps/web starter exists; monorepo cutover in Phase 4 will expand it rather than starting from scratch.
Impact on Phase 5: mcp-tooling browser registry exists; Phase 5 adds the Fastify service layer and live MCP transport wiring around it.
Create a true ui-foundation module that owns interaction architecture, responsive behavior, and preference-state UX.
- layout system and responsive composition rules
- navigation model and wayfinding primitives
- dialog/modal/focus-management primitives
- breakpoint behavior ownership
- theme token system
- preference selectors and persistence shell:
- currency
- period
- language
- keyboard interaction rules
- accessibility enforcement hooks
- UI telemetry wiring
- economics computations
- recommendation logic
- chart business semantics
- provider integration logic
- navigation and focus primitives
- responsive layout contracts
- intent/scope shell for business-question framing
- theme system (
light|dark|system) - preference state shell (
currency|period) - localization shell (
en|fr|zh) - telemetry and HCI contract instrumentation
ui-foundation should support both:
- intent framing (
viability|operations|architecture|executive) - future scope framing aligned with FinOps Framework 2026 business questions
- primary task flows succeed across required breakpoints
- keyboard navigation parity is validated
- critical WCAG violations are zero in core flows
- preference changes persist safely
- UI foundation becomes the owner of surface composition rules
- users can understand what analytical lens they are in and why the presented KPIs/actions are relevant to that lens
Move to the v2 monorepo only after meaningful shared packages exist.
Do not perform monorepo cutover with mostly placeholders.
Cut over when at least these are real and in use:
- one live web app package
- one live service package or service scaffold with real contract traffic
- at least three shared packages with actual consumers
apps/webservices/mcppackages/economics-modulepackages/chart-presentationpackages/health-scorepackages/recommendation-modulepackages/contractsdocs/
- source-of-truth ownership is clear
- contract drift detection exists in CI
- CODEOWNERS / boundaries are enforceable
- cutover runbook has been executed cleanly
Implement the dynamic service track using the accepted ADR stack.
fastify@modelcontextprotocol/sdkzod/ajv
- explain output reasoning
- generate scenario variants
- summarize recommendations for executive or operator audiences
- translate the same result set across intent/scope lenses
- export/report assembly
- support agent-assisted workflows without changing core browser runtime ownership
Keep transport/service logic separate from domain module logic.
- tool schemas match module contracts
- service logic remains thin around domain packages
- MCP tools have fixture parity and validation coverage
Status: complete ✅ — All exit criteria met. v2.0.0-phase-6-exit tag cut on develop (2026-03-21). 77 tests passing.
The original Phase 6 plan prescribed an integration module with OpenOps, Infracost, FOCUS normalization, and direct billing adapters. During Phase 6 planning a more important architectural question was resolved first: what is the extensibility model for FiceCal as a platform? The "WordPress of FinOps" direction was confirmed, requiring a plugin-first foundation before the integration module is built on top of it. The original integration/FOCUS scope is deferred to Phase 8, where it will be delivered as a set of plugins rather than as hardwired integration code.
| Package / deliverable | Tests | Notes |
|---|---|---|
packages/plugin-api |
25 | Zero-dependency FicecalPlugin interface, PluginHost, ThemeRegistry, BillingRegistry, PluginRegistrationError |
| Billing fixture plugins × 4 | 24 | AWS (Cost Explorer), GCP (BigQuery Billing Export), Azure (Cost Management), OpenAI (Usage Export); deterministic ingestMode |
billing.estimate.actual MCP tool |
— | Registered in transport; retrieves normalised billing data from plugin-registered adapter |
billing.compare.period MCP tool |
— | Period-over-period delta, trend, and per-service breakdown |
| Theme plugins × 4 | — | lightThemeContribution, darkThemeContribution, highContrastThemeContribution, oceanBlueThemeContribution in @ficecal/ui-foundation |
BUILT_IN_THEMES array |
— | Ready for ThemeRegistry boot registration in Phase 7 |
| Gap analysis: WordPress of FinOps | — | 8 architectural gaps identified (see section 4G) |
Introduce live external cost and billing context only after runtime contracts are stable.
The following items from the original Phase 6 plan are now deferred to Phase 8, where they will be delivered as plugins via @ficecal/plugin-api:
integration-module— FOCUS-ready normalized cost record mapping layer- OpenOps adapter plugin
- Infracost OSS adapter plugin
- contract commitment dataset support (schema + fixture)
- split allocation and allocation-method support
- recency/completeness metadata support
- service-provider vs host-provider distinction
- delivering plugins without a plugin system would mean hardwiring integrations — a worse architecture than waiting one phase
- the
BillingAdapterContributioninterface now exists as the correct extension point for all provider adapters - Phase 8 integrations will self-register via
PluginHostrather than being imported directly inregistry.ts
- plugin-api is zero-dependency and independently testable ✅
- billing fixtures proven deterministic with real provider export shapes ✅
- billing MCP tools wired via
setBillingRegistry()— no hard provider coupling ✅ - theme contribution system established;
BUILT_IN_THEMESready for ThemeRegistry ✅ - 77 tests passing;
tsc --noEmitclean ✅
Activate the plugin system in the running product. Wire the half-built pieces together, add the hook/filter runtime that makes plugins composable, and expose an admin surface so the plugin system is visible and usable.
ThemeTokenSource structural interface added to @ficecal/ui-foundation — bridges ThemeManager to ThemeRegistry without a hard package dependency. ThemeManager extended with setCustomTheme(id), clearCustomTheme(), getActiveThemeId(), listThemes(). useUiFoundation creates a PluginHost singleton, registers all 4 built-in themes via @ficecal/built-in-themes plugin, passes pluginHost.themes as ThemeTokenSource to ThemeManager. ThemePicker.tsx new component shows all plugin-contributed themes with swatches, descriptions, active indicator; keyboard-accessible (Escape + outside-click). NavBar updated — ThemeToggle replaced by ThemePicker. 13 new ThemeManager tests; 163 total tests passing.
The most important extensibility primitive. Without hooks, plugins can only add; they cannot transform. WordPress's actual moat is add_action / add_filter — 11,000+ interception points.
Proposed API:
// Filters: transform a value
pluginHost.addFilter("billing.estimate.actual.result", (result, context) => {
return applyBudgetCap(result);
});
// Actions: side effects after an event
pluginHost.addAction("theme.applied", (themeId) => {
telemetry.track("theme_changed", { themeId });
});Implementation: HookRegistry class inside packages/plugin-api; priority-ordered listener chains; synchronous filters, async actions.
McpRequestContext.workspaceId exists but nothing scopes data to it. Phase 7 introduces WorkspaceRegistry — plugins, themes, billing adapters, and feature flags scoped per workspace. Required for FiceCal to operate as a hosted multi-tenant SaaS (the WordPress.com model).
A settings panel in apps/web that surfaces:
- list of registered plugins (name, version, status)
- theme picker — shows
ThemeRegistry.list()swatches; applies selected theme - billing provider status — which providers have both fixture and adapter registered (via
BillingRegistry.readyProviders)
Without this panel, the plugin system is invisible to end users. The theme picker wired to ThemeRegistry is the fastest proof that the plugin architecture is real.
Phase 6 billing plugins always return ingestMode: "deterministic". Phase 7 adds the ingestMode: "live" path for the first provider (AWS), returning a 501 Not Implemented response body with upgrade instructions. This stubs the surface without committing to SDK integration, which is Phase 8.
These release quality gates remain part of Phase 7:
- economics fixture parity
- invariants/property tests
- chart payload parity
- critical task-flow smoke tests
- critical accessibility checks
- responsive overflow / focus / tap-target checks
And second-wave gates:
- nav success metrics
- web vitals thresholds
- theme-safety checks
- preference persistence checks
- localization parity checks
- service contract parity
- adapter fixture parity
- FOCUS-field mapping validation where adapters claim support
- framework-alignment evidence for scopes/intents/business-question surfaces
| Deliverable | Status | Notes |
|---|---|---|
| ThemeRegistry → ThemeManager wiring | ✅ | ThemeTokenSource bridge; setCustomTheme / listThemes; 13 new tests |
| ThemePicker component | ✅ | Popover with swatches, active indicator, keyboard-accessible |
| NavBar ThemePicker integration | ✅ | Replaced ThemeToggle; plugin-aware theme selection |
| AdminPanel Sections 1–3 | ✅ | Plugins list, theme picker, billing provider status |
| Live billing 501 stub | ✅ | ingestMode: "live" path wired; LIVE_BILLING_NOT_IMPLEMENTED in transport |
| MCP transport version | ✅ | v0.8.0, phase: 8 |
ThemeRegistryis live and the theme picker works inapps/web✅ Done (Phase 7 P0)- admin panel shows plugins, themes, and billing provider status ✅ Done (Phase 7 P1)
- live billing toggle surface exists (501 stub until Phase 9) ✅ Done (Phase 7 P2)
HookRegistryexists and at least one filter is in use ⬜ Carried to Phase 9 P0WorkspaceRegistryisolates billing data perworkspaceId⬜ Carried to Phase 9 P1- release evidence is generated consistently ⬜
- contract drift is blocked automatically ⬜
- claims of external framework/spec alignment are supported by explicit evidence artifacts ⬜
Status: partially complete — P0–P5 done (2026-03-21). Integration adapters (8B), registry repo (8C), and chargeback tool (8D) deferred to Phase 9.
| Package / deliverable | Tests | Notes |
|---|---|---|
packages/schemas — NormalizedCostRecord v2 |
77 | SCHEMA_VERSION = "2.0.0"; ~63/77 FOCUS columns; 7 enum types; FOCUS_V1_3_GAP_COLUMNS; upgradeToV2() migration helper |
packages/plugin-registry-client |
63 | RegistryClient: browse/find/listTags/verifyBundle/checkReadiness; SHA-256 via Web Crypto; in-memory cache; typed error classes |
packages/create-ficecal-plugin |
59 | npx create-ficecal-plugin CLI; 4 plugin types (billing/theme/mcp/full); pure scaffold functions |
billing.commitment.status MCP tool |
33 | All 7 FOCUS CommitmentDiscount columns; AWS/GCP/Azure fixtures; utilisationRate + wastedSpend summary; toolCount → 6 |
FinOps Framework 2026 types in @ficecal/contracts |
— | 6 domains, 3 maturity levels, 4 assessment interfaces, AiMlCostAssessment |
AdminPanel Section 4 — Registry Browser |
— | Lazy-load; tag/search filters; plugin cards with readiness dots, tag chips, install issues |
Deliver genuine FOCUS 1.3 alignment through NormalizedCostRecord v2 (FOCUS-column-mapped), real provider adapter integrations, and a GitHub-based community plugin registry. All integrations are plugins via @ficecal/plugin-api.
Replace the Phase 1 NormalizedCostRecord with a FOCUS 1.3-mapped schema covering all 77 Cost and Usage Dataset columns plus the 13-column Contract Commitment Dataset.
Must implement (blocks any FOCUS alignment claim):
| FOCUS category | Columns | Count |
|---|---|---|
| Account | BillingAccountID, BillingAccountName, BillingAccountType, SubAccountID, SubAccountName, SubAccountType | 6 |
| Billing | BilledCost, BillingCurrency, ConsumedQuantity, ConsumedUnit, EffectiveCost, ListCost, ListUnitPrice, ContractedCost, ContractedUnitPrice | 9 |
| Charge | ChargeCategory, ChargeClass, ChargeDescription, ChargeFrequency | 4 |
| Charge Origination | ProviderName, ServiceProviderName (1.3), HostProviderName (1.3), PublisherName, InvoiceID, InvoiceIssuer | 6 |
| Service | ServiceCategory, ServiceName, ServiceSubcategory | 3 |
| Location | RegionID, RegionName, AvailabilityZone | 3 |
| Timeframe | BillingPeriodStart, BillingPeriodEnd, ChargePeriodStart, ChargePeriodEnd | 4 |
| Resource + Tags | ResourceID, ResourceName, ResourceType, Tags | 4 |
| SKU | SKUID, SKUMeter, SKUPriceID, SKUPriceDetails | 4 |
| Pricing | PricingCategory, PricingCurrency, PricingQuantity, PricingUnit, PricingCurrencyListUnitPrice, PricingCurrencyContractedUnitPrice, PricingCurrencyEffectiveCost | 7 |
| Allocation (FOCUS 1.3 new) | AllocatedMethodDetails, AllocatedMethodID, AllocatedResourceID, AllocatedResourceName, AllocatedTags | 5 |
| Commitment Discount | CommitmentDiscountCategory, CommitmentDiscountID, CommitmentDiscountName, CommitmentDiscountQuantity, CommitmentDiscountStatus, CommitmentDiscountType, CommitmentDiscountUnit | 7 |
| Capacity Reservation | CapacityReservationID, CapacityReservationStatus | 2 |
| Contract Dataset (FOCUS 1.3 new supplemental) | ContractApplied, ContractCommitmentCategory, ContractCommitmentCost, ContractCommitmentDescription, ContractCommitmentID, ContractCommitmentPeriodEnd, ContractCommitmentPeriodStart, ContractCommitmentQuantity, ContractCommitmentType, ContractCommitmentUnit, ContractID, ContractPeriodEnd, ContractPeriodStart | 13 |
Mapping Phase 1 NormalizedCostRecord fields → FOCUS equivalents:
| Phase 1 field | FOCUS 1.3 equivalent |
|---|---|
amountType (actual/amortized/blended/list/allocated) |
chargeCategory + chargeClass |
allocationScope + allocationMethod + allocationSource |
allocatedMethodID + allocatedMethodDetails |
providerRole (service-provider/host-provider) |
serviceProviderName + hostProviderName |
commitmentType + commitmentReference |
Contract Commitment Dataset columns |
dataCompleteness + dataRecencyTimestamp |
FOCUS 1.3 data recency/completeness metadata |
All adapters self-register via PluginHost.contributions.billingAdapters:
| Plugin | Ingests from | Target | Mode |
|---|---|---|---|
@ficecal/integration-openops |
OpenOps API export | NormalizedCostRecord v2 |
deterministic → live |
@ficecal/integration-infracost |
Infracost JSON output | NormalizedCostRecord v2 |
deterministic → live |
@ficecal/billing-aws v2 |
AWS Cost Explorer SDK | NormalizedCostRecord v2 |
live |
@ficecal/billing-gcp v2 |
GCP BigQuery Billing Export | NormalizedCostRecord v2 |
live |
@ficecal/billing-azure v2 |
Azure Cost Management REST API | NormalizedCostRecord v2 |
live |
@ficecal/billing-openai v2 |
OpenAI Usage API | NormalizedCostRecord v2 |
live |
A GitHub-hosted plugin registry — zero infrastructure, fully auditable, community PR model. Modeled on Homebrew taps, Obsidian plugin list, and VS Code Marketplace patterns.
Registry repo: duksh/ficecal-plugin-registry (public)
ficecal-plugin-registry/
plugins/
index.json ← master manifest: all registered plugins
ficecal-theme-high-contrast.json ← per-plugin manifest
ficecal-billing-snowflake.json
themes/
index.json ← themes-only index for theme picker
schemas/
ficecal-plugin.schema.json ← ficecal-plugin.json JSON Schema v1
CONTRIBUTING.md ← submission guide
.github/workflows/
validate-plugin.yml ← CI validates ficecal-plugin.json on every PR
plugins/index.json entry shape:
{
"id": "@community/ficecal-theme-ocean-blue",
"name": "Ocean Blue Theme",
"version": "1.0.0",
"author": "community-contributor",
"contributions": ["themes"],
"stability": "stable",
"minFicecalVersion": "2.0.0",
"bundleUrl": "https://cdn.jsdelivr.net/gh/contributor/ficecal-theme-ocean-blue@1.0.0/dist/plugin.js",
"sha256": "abc123...",
"tags": ["theme"]
}packages/plugin-registry-client in FiceCal monorepo:
- Fetches
index.jsonfromhttps://raw.githubusercontent.com/duksh/ficecal-plugin-registry/main/plugins/index.json - Caches manifest with configurable TTL (default: 1 hour)
- Validates
sha256of downloaded plugin bundles beforePluginHost.register() - Supports offline fallback (uses last-known-good cached manifest)
Community publish flow:
- Developer runs
npx create-ficecal-plugin→ generates plugin withficecal-plugin.json - Publishes bundle to their own GitHub Releases
- Opens PR to
ficecal-plugin-registryadding their entry toplugins/index.json - GitHub Actions CI: validates schema, checks
minFicecalVersion, verifiessha256resolves - Maintainer merges PR → plugin appears in FiceCal admin panel "Browse plugins" tab within 1 hour (TTL)
Why GitHub-based:
- zero infrastructure cost — no registry server, no database
- trust model — every plugin registration is a public PR with audit trail
jsdelivr.netserves bundles from GitHub Releases at CDN scale for free- precedent: Homebrew taps, Obsidian community plugins, Raycast extensions
| Framework capability | Deliverable | Dependency |
|---|---|---|
| Invoicing & Chargeback | MCP tool billing.chargeback.allocate + chargeback panel in apps/web |
FOCUS Allocation columns (8A) |
| Executive Strategy Alignment (2026 new) | executive-strategy-module — multi-year investment framing, leadership KPI narrative, strategic decision signals |
executive intent/scope surfaces from Phase 3 |
| FinOps Assessment | finops-assessment-module — crawl/walk/run maturity scoring against all 22 capabilities |
Admin panel integration |
| Data Ingestion (live) | FOCUS-native ingestion pipeline from real provider data | 8B adapter plugins |
npx create-ficecal-plugin— scaffolds plugin withFicecalPluginboilerplate,ficecal-plugin.json, vitest harness, GitHub Actions publish + registry-PR workflowficecal-plugin-sdkpackage — mockPluginHost, mockBillingRegistry, theme token validator,FocusValidatorforNormalizedCostRecordv2 schema compliance
NormalizedCostRecordv2 at ~82% FOCUS column coverage ✅ Done (Phase 8 P0) — 13 columns deferred inFOCUS_V1_3_GAP_COLUMNS- Contract Commitment Dataset + MCP tool ✅ Done (Phase 8 P3) —
billing.commitment.statuscovers all 7 CommitmentDiscount columns npx create-ficecal-plugingenerates a working, registry-submittable plugin ✅ Done (Phase 8 P2) — 4 plugin types, 59 testsplugin-registry-clientwith SHA-256 bundle verification ✅ Done (Phase 8 P1) — 63 tests- Allocation columns;
billing.chargeback.allocateMCP tool functional ⬜ Deferred to Phase 9 P4 - At least one live billing adapter proven in staging ⬜ Deferred to Phase 9 P3
duksh/ficecal-plugin-registryrepo live with indexed plugins ⬜ Deferred to Phase 9 P1- Integration adapter plugins (8B: OpenOps, Infracost, billing-aws/gcp/azure/openai v2) ⬜ Deferred to Phase 9
Clear Phase 8 carryover items first (HookRegistry, WorkspaceRegistry, plugin registry repo, live billing, chargeback tool), then make the plugin ecosystem safe for community contributions — sandboxing, signed contracts, and production hardening.
| Priority | Deliverable | Rationale |
|---|---|---|
| P0 | HookRegistry — pluginHost.addFilter / addAction in packages/plugin-api |
✅ Done — 44 vitest tests; priority-ordered filter/action chains; billing.estimate.actual.result production hook; plugin.registered, plugin.disabled, plugin.enabled, featureflag.changed actions; registeredFilters / registeredActions introspection |
| P1 | duksh/ficecal-plugin-registry repo — create index.json with at least 2 entries |
✅ Done — repo created at github.com/duksh/ficecal-plugin-registry; plugins/index.json (version/updatedAt/plugins shape); 2 seed entries (high-contrast + ocean-blue themes); JSON Schema v7 validation; CI workflow (schema, HTTPS, sha256, unique IDs, semver); CONTRIBUTING.md + README; DEFAULT_REGISTRY_INDEX_URL updated in plugin-registry-client |
| P2 | WorkspaceRegistry — scope plugins, themes, billing adapters per workspaceId |
✅ Done — 23 vitest tests; disablePluginForWorkspace, enablePluginForWorkspace, listPluginsForWorkspace, listThemesForWorkspace, listAdaptersForWorkspace; workspace.plugin.disabled/enabled hooks |
| P3 | Live AWS billing — replace 501 stub with real Cost Explorer SDK call | ✅ Done — aws-billing-plugin.ts v2.0.0; real GetCostAndUsageCommand; MONTHLY/UnblendedCost/by SERVICE; mapResultsToLineItems() → BillingPeriodSummary; dynamic SDK import; 501 stub retired |
| P4 | billing.chargeback.allocate MCP tool |
✅ Done — FOCUS 1.3 Allocation columns (AllocatedCost, AllocatedMethodID, AllocatedMethodDetails, AllocatedResourceID, AllocatedResourceName, AllocatedTags); even/proportional/tag-based methods; AWS (2 resources, 5 consumers), GCP (1 resource, 3 consumers), Azure (1 resource, 3 consumers) fixtures; toolCount → 7; transport v0.9.0 / phase 9; 32 vitest tests |
- Plugin sandboxing — separate Web Worker or Deno worker per plugin with resource limits; billing plugins cannot cross-read workspace data ⬜ Carried to Phase 10
- Signed plugin manifests — GPG or code-signing for plugins distributed via the marketplace; version pinning in a
ficecal-plugin-lock.json⬜ Carried to Phase 10 ficecal-plugin.jsonstandard — canonical plugin manifest (id, version,requires: ["ficecal>=2.0.0"], contribution declarations, signing key) ⬜ Carried to Phase 10- Auto-update pipeline — plugins check for new versions against the registry; opt-in auto-update with rollback; changelog surfaced in admin panel ⬜ Carried to Phase 10
finops-assessment-module— crawl/walk/run scoring engine consumingFinOpsCapabilityDomainboundary types from@ficecal/contracts✅ Done —@ficecal/finops-assessmentpackage; 6 domain scorers; 21 signal flags; modal maturity tie-break-to-lower; top-3 cross-domain recommendations; 58 tests;finops.assessment.runMCP tool; toolCount → 8; transport v0.10.0; 36 MCP integration tests
HookRegistryexists and at least one filter is active ✅ Done — 44 tests;billing.estimate.actual.resultproduction filter; plugin lifecycle actionsWorkspaceRegistryisolates billing data perworkspaceId✅ Done — 23 tests; per-workspace plugin/theme/adapter visibilityduksh/ficecal-plugin-registrylive with at least 2 indexed plugins ✅ Done — repo live; 2 seed theme plugins; CI validation;DEFAULT_REGISTRY_INDEX_URLupdatedbilling.chargeback.allocatefunctional;shared-cost-allocationscope can be unguarded ✅ Done — even/proportional/tag-based; AWS/GCP/Azure fixtures; 32 tests; toolCount=7; transport v0.9.0- at least one live billing adapter (AWS) proven; 501 stub retired ✅ Done —
aws-billing-plugin.tsv2.0.0; real Cost ExplorerGetCostAndUsageCommand; 501 path removed finops-assessment-moduledelivers crawl/walk/run scoring ✅ Done — 6 domain scorers; 58 tests;finops.assessment.runMCP tool; toolCount → 8; transport v0.10.0- billing MCP tools upgraded from
BillingPeriodSummarytoNormalizedCostRecordv2 ✅ Done — transport v0.11.0; FOCUS dead end resolved - a community plugin installed from the marketplace cannot access data from another workspace ⬜ Carried to Phase 10 — plugin sandboxing (Web Worker isolation) deferred; architectural effort
- plugins with invalid or missing signatures are rejected at registration ⬜ Carried to Phase 10 — signed
ficecal-plugin.jsonmanifests deferred - auto-update works for at least one community theme plugin without a full FiceCal redeployment ⬜ Carried to Phase 10 — auto-update pipeline deferred
Build the intelligence layer that makes FiceCal actionable rather than analytical. Ship anomaly detection, assessment×billing correlation, and model routing optimization before adding more data sources. Then deliver all-provider AI billing adapters using ficecal-model-lens as the pricing oracle. Sandbox/signing/auto-update carryover from Phase 9 closes out in Phase 10B.
| Priority | Deliverable | Rationale |
|---|---|---|
| P0 | billing.anomaly.detect MCP tool |
Highest practitioner value, lowest effort; converts FiceCal from passive dashboard to active FinOps partner; spike detection over NormalizedCostRecord[]; model-lens enriches alert with model name + per-token rate + projected overage ✅ Done — toolCount → 9; transport v0.12.0; 28 tests |
| P1 | packages/billing-ai-providers — AiProviderBillingAdapter interface + normalize.ts shared mapper |
Foundation for all provider adapters; token counts × ModelPricingReference → NormalizedCostRecord v2; shared by all P2 adapters ✅ Done — 102 tests; lookupModelPricing() 4-pass fuzzy; FOCUS pricingCategory: "standard" |
| P2 | AI provider usage-API adapters × 6 — Anthropic, OpenAI, Gemini, Mistral, DeepSeek, Alibaba | Pricing pre-solved by model-lens; each adapter only needs provider usage API (token counts); all 6 achievable in one sprint; Alibaba CNY→USD via Phase 1 StaticForexAdapter ✅ Done — all 6 deterministic adapters; AI_PROVIDER_ADAPTERS registry map; CredentialsRequiredError |
| P3 | finops.assessment.correlate MCP tool |
assessment × billing × model-lens correlation; topRecommendations re-ranked by ROI (spend context + improvement multiplier); totalAddressableWaste computed; 7 correlation rules ✅ Done — 29 integration tests; toolCount → 10; CorrelationBillingRegistry wired to merged cloud+AI registry |
| P4 | billing.routing.optimize MCP tool |
Top-3 model substitution opportunities ranked by estimatedMonthlySaving; compares actual spend per model vs cheaper equivalent from model-lens ✅ Done — 26 integration tests; 17-entry ROUTING_CATALOG; 4-tier downgrade; toolCount → 11; transport v0.13.0 |
| UI | IntelligencePanel in apps/web — three-section UI for all Phase 10A tools |
Closes practitioner gap — routing/anomaly/correlation all visible in the web app ✅ Done — parallel MCP fetch() calls; independent load/error states; NavBar link; tsc --noEmit clean |
| Priority | Deliverable | Rationale |
|---|---|---|
| P5 | Plugin sandboxing — Web Worker or Deno worker per plugin with resource limits | Community plugin isolation; billing plugins cannot cross-read workspace data ⬜ |
| P6 | Signed plugin manifests — GPG / code-signing; reject unsigned community plugins | ficecal-plugin-lock.json version pinning; signing key in ficecal-plugin.json ⬜ |
| P7 | Auto-update pipeline — plugins check registry for new versions; opt-in auto-update with rollback | Changelog surfaced in AdminPanel; at least one community theme plugin proven ⬜ |
namespace: billing
toolId: billing.anomaly.detect
stability: beta
Input:
workspaceId: string
currentPeriodStart: string // ISO date
currentPeriodEnd: string
baselinePeriodStart: string
baselinePeriodEnd: string
thresholdPercent?: number // default 50 — flag anything >50% over baseline
providers?: string[] // optional filter: ["anthropic", "openai", ...]
Output (BillingAnomalyOutput):
anomalies: AnomalyRecord[] // ranked by deltaAmount DESC
totalCurrentSpend: string // decimal-safe
totalBaselineSpend: string
totalDeltaPercent: number
overallSeverity: "none" | "warning" | "critical"
ingestMode: "deterministic" | "live"
AnomalyRecord:
service: string // FOCUS ServiceName
modelId?: string // from model-lens if resolvable
currentSpend: string
baselineSpend: string
deltaPercent: number
deltaAmount: string
severity: "warning" | "critical" // warning >50%, critical >100%
pricePerMillion?: number // from ModelPricingReference if available
projectedMonthlyOverage?: string // deltaAmount annualised to calendar month
recommendation: string
appliedIds: ["billing.anomaly.threshold.relative-delta.v1", "billing.anomaly.severity.2x-critical"]
namespace: finops
toolId: finops.assessment.correlate
stability: beta
Input: same flat signal flags as finops.assessment.run
+ workspaceId: string
+ periodStart: string
+ periodEnd: string
Output (FinOpsAssessmentCorrelateOutput):
// all FinOpsFrameworkAssessment fields
correlatedRecommendations: CorrelatedRecommendation[]
totalAddressableWaste: string // sum of estimatedRecovery across domains
billingPeriod: { start, end }
billingRecordCount: number
ingestMode: "contextual" // never "deterministic" — depends on live billing
CorrelatedRecommendation:
domain: string
domainScore: number
recommendation: string
relevantSpend: string // actual $ in scope for this domain
estimatedRecovery: string // relevantSpend × improvement_multiplier × (1 - score/100)
roiRank: number // 1 = highest ROI
evidenceText: string // e.g. "$82K/month Bedrock with no token attribution"
Domain → service category mapping:
| Domain | Service categories |
|---|---|
understand |
All (visibility gap affects everything) |
quantify |
Compute, Storage |
optimize |
EC2, RDS, EKS, Lambda, Bedrock |
managePractice |
All |
sustainability |
Compute-intensive |
aiMl |
AI and Machine Learning, Bedrock, SageMaker, OpenAI API, Anthropic |
namespace: billing
toolId: billing.routing.optimize
stability: alpha
Input:
workspaceId: string
periodStart: string
periodEnd: string
maxRecommendations?: number // default 3
Output:
opportunities: RoutingOpportunity[]
totalEstimatedMonthlySaving: string
ingestMode: "contextual"
RoutingOpportunity:
currentModelId: string
currentMonthlySpend: string
currentPricePerMillion: number
suggestedModelId: string
suggestedPricePerMillion: number
estimatedMonthlySaving: string
savingPercent: number
rationale: string // e.g. "Haiku handles classification at 70% lower cost"
caveat: string // e.g. "Validate quality for your task type before switching"
billing.anomaly.detectfunctional; 28 integration tests ✅ Done (Phase 10 P0)packages/billing-ai-providersinterface established; all 6 provider adapters (Anthropic/OpenAI/Gemini/Mistral/DeepSeek/Alibaba) deliveringNormalizedCostRecord[]withdataCompleteness: "partial"✅ Done (Phase 10 P1+P2) — 102 testsfinops.assessment.correlatefunctional;totalAddressableWastecomputed from real billing records ✅ Done (Phase 10 P3) — 29 integration testsbilling.routing.optimizereturns ≥1 opportunity for fixture workspace with mixed model spend ✅ Done (Phase 10 P4) — 26 integration tests; toolCount → 11; transport v0.13.0IntelligencePanelinapps/websurfaces all three tools with independent load/error states ✅ Done (Phase 10 UI) — routing + anomaly + correlation sections; NavBar link added;tsc --noEmitclean- §4B Framework 2026 coverage matrix updated to reflect Phase 10A deliverables ✅ Done
- transport version bumped to v0.14.0 (one bump per new tool group) ⬜ At v0.13.0 — bump deferred to Phase 10B completion
- Phase 9 carryover: plugin sandboxing ⬜, signed manifests ⬜, auto-update ⬜ Phase 10B — in progress
- integration adapters (OpenOps, Infracost) explicitly deferred to Phase 11 — not an exit blocker ✅ Confirmed deferred
The v2 UX should be framed as intent-first, mode-aware, explainable analytical UX.
- Intent = why the user is here
- viability
- operations
- architecture
- executive
- Scope = what business or FinOps question is being answered
- baseline unit economics
- optimization
- architecture/workload placement
- executive strategy
- future: commitment management
- future: shared-cost allocation
- Mode = how much complexity they want
- quick
- operator
- architect
This is stronger than using only complexity modes. It separates:
- user goal
- business question context
- information density
- make the primary path unmistakably simple
- preserve advanced exploration for expert users
- make output interpretation central, not secondary
- keep chart semantics trustworthy and deterministic
- reduce cognitive load without collapsing analytical power
- make the active scope and intent visible so users understand why metrics and actions are shown
- calculate baseline viability
- load and compare scenario states
- understand why a KPI is flagged
- see what action to take next
- switch audience framing when interpreting recommendations
- switch scope or business-question framing without losing state
- navigate docs/glossary only when needed
Authored by: FinOps Product Owner / UX review. Basis: live comparison of localhost:4321 (vantage-models Astro site) against https://duksh.github.io (FiceCal, richer product shell); screenshotted and analyzed 2026-03-23.
The ficecal-model-lens site (AI model pricing comparison table, Astro + sql.js) is the upstream data surface for FiceCal v2's model catalog. It is publicly deployed at duksh.github.io and is also the entry point many FinOps practitioners first encounter. The current experience drops users directly into a raw data table — no hero, no framing, no guided first action — while the FiceCal shell at the same domain has a structured hero, feature cards, and calculator interface. The disconnect between the two creates immediate trust and comprehension failure for first-time visitors.
| Gap | Name | Observation | Impact |
|---|---|---|---|
| G1 | Zero value proposition above the fold | First visible content is a dense data table. No headline, no tagline, no "this helps you…" | Visitors have no reason to stay within 3 seconds |
| G2 | Brand confusion | Header reads "vantage.sh/models — Powered by Vantage" on what is the user's deployed domain. Visitors assume this is a Vantage product. | Brand trust = zero; ownership signal is absent |
| G3 | No orientation or guided first action | No tooltip, no "start here", no empty-state guidance on what to filter or why | New users have no path forward |
| Gap | Name | Observation | Impact |
|---|---|---|---|
| G4 | Data without insight | Raw integers (e.g. 200000) with no cost-per-token signal, no color-coded zone badges, no "cheap vs expensive" framing |
Numbers have no FinOps meaning |
| G5 | Empty cells rendered as - |
Dozens of cells show bare - with no explanation |
Users cannot tell if - means unavailable, not applicable, free, or data gap — procurement decisions blocked |
| G6 | No FinOps job-to-be-done framing | The site does not surface the 3 primary FinOps practitioner questions: Which model is cheapest for my use case? Which vendor? How do Anthropic vs AWS Bedrock compare for the same model? | Visitors cannot map the data to their actual work |
| G7 | Column headers lack units and definitions | "Max Input Tokens" and "Max Output Tokens" appear with no tooltip, no cost context, no per-token price linkage | Data literacy barrier; pricing columns not visible on first load |
| Gap | Name | Observation | Impact |
|---|---|---|---|
| G8 | No social proof or trust signal | No data-source attribution, no last-updated timestamp, no testimonial or authority link | FinOps practitioners making budget decisions need provenance; no attribution = no credibility |
| G9 | Power features invisible | The SQL query builder (+ Add Query, Run Query) is present but completely undiscoverable for newcomers. No "try this query" suggestion or tooltip. |
Power-user adoption ceiling hit immediately |
| G10 | No responsive / mobile layout | Wide data table is unreadable on mobile. FinOps practitioners share links in Slack and email. | Broken mobile experience kills viral adoption |
| Priority | Gap | Resolution | Effort | Phase |
|---|---|---|---|---|
| P1 | G1 | Add 2-line hero above the table: bold headline + 1-sentence value prop ("Compare AI model pricing and context limits across AWS, Anthropic, DeepSeek and more — for FinOps-informed procurement.") | XS | 13 |
| P2 | G2 | Replace "Powered by Vantage" with project attribution or remove entirely; update <title> and <meta name="description"> |
XS | 13 |
| P3 | G6 | Add 3 use-case filter shortcut chips above the table: "Find cheapest for coding", "Compare by vendor", "Show reasoning models only" | S | 13 |
| P4 | G4 | Surface a cost-per-1M-tokens column (input + output blended) as a default visible column — derived from existing pricing data | S | 13 |
| P5 | G5 | Replace bare - with a title-attribute tooltip: "Data not reported by this vendor" |
XS | 13 |
| P6 | G7 | Add <abbr title="…"> or popover tooltips on column headers with plain-English definition and FinOps relevance |
S | 13 |
| P7 | G3 | Add a first-visit callout banner (dismissable, localStorage-persisted): "New here? Start by selecting a use case above ↑" | XS | 13 |
| P8 | G9 | Add 2–3 "Try this query" example buttons with pre-filled SQL (e.g. cheapest input token rate, models with >100k context, Anthropic vs AWS Bedrock) | M | 13 |
| P9 | G8 | Add data-source attribution footer: source (AWS Bedrock API, Anthropic API), last-scraped date pulled from data.json |
XS | 13 |
| P10 | G10 | Add responsive CSS: horizontal scroll on table below 768px breakpoint; hero and chips stack vertically | S | 13 |
Goal: Transform the ficecal-model-lens from a raw data dump into a practitioner-friendly FinOps reference surface.
Scope (all items P1–P10 above):
- Files to touch:
src/pages/index.astro,src/styles/(or inline Tailwind),src/components/(hero component, chip component, column header tooltip),public/data.json(ensurelastUpdatedfield present) - No backend changes required
- All XS items completable in a single sitting
- S/M items completable in one sprint (3–5 days)
Definition of done:
- A first-time FinOps practitioner landing on the page can answer "what is this, who is it for, and what should I do first?" within 3 seconds
- The pricing / token columns have visible cost context (per-1M-token blended rate)
- Empty cells carry a machine-readable and human-readable explanation
- Column headers are self-documenting
- Data source and freshness are visible without scrolling
- At least 2 example queries are surfaced for discovery
- Site is usable on a 375px viewport
Success metric: Bounce rate reduction ≥ 15% (measured via plausible.io or equivalent privacy-respecting analytics if instrumented).
- deterministic economics fixtures
- property/invariant testing
- chart payload fixtures
- breakpoint smoke checks for core flows
- keyboard/focus validation for primary surfaces
- baseline verification of intent/scope switching state preservation
- HCI telemetry collection and trend analysis
- nav task success instrumentation
- web vitals thresholds
- theme management recovery tests
- localization and preference persistence tests
- framework-aligned scope/task success instrumentation
- MCP schema parity tests
- integration adapter fixtures
- contract compatibility matrix across modules
- FOCUS mapping fixtures for commitment, allocation, recency/completeness, and provider-role semantics
Trying to implement full UI foundation, service layer, monorepo cutover, and provider adapters at once.
- enforce phased delivery
- require exit criteria before advancing
- keep service/integration work on a separate but synchronized track
Architectural cleanup breaks trusted calculations or familiar flows.
- baseline freeze first
- fixture parity and chart parity before refactoring ownership
- compatibility aliases until evidence is complete
Modules exist formally, but index.html still makes the true decisions.
- move authority with contracts, not just files
- reduce page shell to orchestration and rendering composition only
Billing adapters dominate effort before core product modularization is stable.
- prioritize OpenOps and Infracost first
- gate direct billing adapters on proven data model and security readiness
Metrics become noisy or misleading if instrumentation lands before flow stability.
- instrument critical stable flows first
- align event naming to one source of truth
- defer exhaustive analytics until tasks are structurally settled
The roadmap or product positioning overstates alignment with Framework 2026 or FOCUS 1.3 before the necessary scope, data, or evidence exists.
- separate strategic alignment from formal support claims
- require explicit alignment evidence per capability or dataset claim
- add spec/framework support checklist to release readiness
economics-module exists as the canonical compute kernel and matches current live parity.
chart-presentation, health-score-module, and recommendation-module consume canonical contracts and are independently testable.
ui-foundation owns navigation, layout, focus, theming, preference UX shell, and intent/scope framing.
FiceCal can clearly express Framework 2026-aligned business-question surfaces without breaking current product usability.
MCP service layer adds validated assistant-driven capabilities without polluting domain boundaries.
Integration module brings external cost context safely, beginning with normalized mapping, OpenOps, and Infracost.
FiceCal supports the first meaningful FOCUS-ready integration features for commitment, allocation, and metadata semantics where adapters provide them.
These issues translate the plan into concrete implementation-sized work items.
- define parity fixture inventory for current live calculator states
- capture current chart rendering baselines for representative scenarios
- document current Framework 2026 / FOCUS 1.3 baseline coverage claims and non-claims
- define the list of parity-protected versus intentionally changing behaviors
- create
economics-moduleinput and output schemas - define compatibility mapping from
core-economicstoeconomics-module - create formula traceability registry and invariant test suite
- define normalized cost-record contract v1
- implement validation rules for amount types, allocation semantics, and freshness metadata
define✅ Done —ModelPricingReferencecontract and validation suitepackages/schemas/model-catalog/index.ts(PR #118)define adapter boundary schemas for✅ Done —duksh/ficecal-model-lenssource ingestionpackages/integrations/models-pricing/src/transform.ts(PR #118)- decide whether image generation economics lives inside
ai-token-economicsor as a siblingai-image-economicsmodule (Gap 1) — decision taken:pricingUnitdispatch insideai-token-economics; implement dispatch branch (Phase 2) implement✅ Done — PR #118pricingSourceTypevalidation and consumer surfacing rules (Gap 2)implement✅ Done — PR #118duksh-models-adaptersnapshot versioning convention using content hash + ingestion date (Gap 3)publish approved benchmark list v1 as a versioned artifact in✅ Done — PR #118model-catalog-contracts(Gap 4)- define forex source hierarchy, injection boundary, and staleness rules; implement ECB feed adapter with static fallback (Gap 5) — next Phase 1 priority
extract✅ Donechart-presentationto consume canonical economics payloadsextract✅ Done (PR #123)health-score-modulewith deterministic inputs and outputsextract✅ Done (PR #124)recommendation-modulewith audience-aware explanation payloadsextract✅ Done (PR #125)ai-token-economicswith per_image dispatch (Gap 1)extract✅ Done (PR #131)multi-tech-normalizationwith efficiency indexextract✅ Done (PR #132)sla-slo-sli-economics— error budget, downtime cost, reliability ROIestablish✅ Done (PR #133)economics-moduleumbrella registry and plugin interfaceimplement✅ Done (PR #134)budgeting-forecasting— variance, OLS trend, compound growthimplement✅ Done (PR #135)reference-evidence— evidence catalog and query engineimplement✅ Done (PR #136)demo-scenarios— 6 canonical scenarios with live engine assertionsharden✅ Done (PR #137, 7 engine contracts, 29 integration tests)qa-modulearound the full chain
implement✅ Done —ui-foundation— navigation and focus primitives (layout system, responsive composition, breakpoint ownership, dialog/modal/focus-management)BREAKPOINTS,getFocusableElements/getFirstFocusable/getLastFocusable,KeyboardShortcutRegistry(PR #138)implement✅ Done —ui-foundation—intent/scope/modestate shell; FinOps Framework 2026-aligned scope taxonomy; preference persistence and deep-link rulesIntentScopeStatewith history stack (max 50), autoScope affinity,toQueryString/fromQueryString;PreferenceStorewithStorageAdapterinjectable (PR #138)implement✅ Done —ui-foundation— theme system (light|dark|system), CSS custom properties, localStorage persistence, no-FWOT guardThemeManagerwithTHEME_TOKENSCSS custom properties,apply()synchronous,MediaQuerySystemThemeAdapter(PR #138)implement✅ Done —ui-foundation— localization shell (en|fr|zhstubs, i18n infrastructure)LocalizationShellwith en/fr/zh CATALOG (~35 keys each),{{var}}interpolation, runtime locale switching (PR #138)implement✅ Done —ui-foundation— keyboard interaction rules and accessibility enforcement (WCAG critical violations → zero in primary analytical flows)KeyboardShortcutRegistrywithctrl+kdescriptor normalization,contrastRatio/sRgbToLinear/relativeLuminance,WCAG_CONTRASTthresholds (PR #138)implement✅ Done — 12-eventui-foundation— UI telemetry wiring contracts (event naming schema; instrument intent/scope switching and recommendation interpretation flows)TelemetryEventdiscriminated union,BufferedTelemetryEmitterfor test assertions,ConsoleTelemetryEmitter(PR #138)update✅ Done —apps/webto consumeui-foundationlayout, theme, and preference primitivesThemeToggle,IntentScopeBar,useUiFoundation()hook,i18n.t()in App.tsx (PR #139)- validate primary task flows across required breakpoints and keyboard navigation (deferred to Phase 5 Playwright evidence gate)
- define monorepo cutover readiness checklist
- establish package boundaries and ownership rules
- move shared contracts and modules into real consumer-backed packages
- execute cutover only after reuse thresholds are met
- expose MCP tools for explanation, scenario generation, and audience reframing
- ensure MCP tool schemas mirror canonical module contracts
- add fixture-based validation for tool responses
- expose model-choice comparison and AI cost tradeoff MCP tools only after normalized model views are contract-stable
deliver✅ Done — 25 testspackages/plugin-api— zero-dependencyFicecalPlugininterface,PluginHost,ThemeRegistry,BillingRegistrydeliver billing fixture plugins × 4 (AWS/GCP/Azure/OpenAI) with deterministic✅ Done — 24 transport testsBillingAdapterContributiondeliver✅ Donebilling.estimate.actualandbilling.compare.periodMCP tools registered in transportdeliver theme contribution plugins × 4 in✅ Done —@ficecal/ui-foundationBUILT_IN_THEMESready for boot registrationgap analysis against "WordPress of FinOps" target✅ Done — 8 gaps identified and prioritized in section 4G- build integration-module around normalized cost-record ingestion → deferred to Phase 8 (as plugin)
- add OpenOps mapping into normalized records → deferred to Phase 8
- add Infracost mapping into normalized records → deferred to Phase 8
- add commitment-support fields, split allocation, and provider-role semantics → deferred to Phase 8
- add recency/completeness evidence handling and UI degradation paths → deferred to Phase 8
wire✅ Done (2026-03-21) —ThemeRegistry→ThemeManager; boot fromBUILT_IN_THEMESat app startupThemeTokenSourcestructural interface +ThemeManagerconstructor 4th param;useUiFoundationcreatesPluginHost, registers@ficecal/built-in-themesplugin, passespluginHost.themes; 163 testsimplement live theme picker in✅ Done (2026-03-21) —apps/webusingThemeRegistry.list()with swatch previewsThemePicker.tsx+ full CSS;NavBarupdated;@ficecal/plugin-apiadded toapps/webruntime deps- implement
HookRegistry(addFilter/addAction) inpackages/plugin-api— at least one filter in production use - implement
WorkspaceRegistry— scope all plugin contributions perworkspaceIdfromMcpRequestContext - implement admin panel in
apps/web— plugin list, theme picker panel, billing provider status (BillingRegistry.readyProviders) - add live billing path stub (
ingestMode: "live"→ 501 with upgrade instructions) to at least one provider plugin - add feature-flag guard or "coming soon" degradation state for
commitment-managementandshared-cost-allocationscopes (no backing content until Phase 8) - enrich
@ficecal/reference-evidenceEVIDENCE_CATALOG with per-capability FiceCal evidence entries (cross-reference section 4B Framework/FOCUS coverage matrices) - add economics fixture parity gate, invariants gate, chart parity gate to CI
- add task-flow smoke tests and critical accessibility checks
- block releases that make unsupported Framework 2026 / FOCUS alignment claims
- bump
services/mcp/package.jsonversion from0.5.0→0.6.0to match health endpointversion: "0.6.0"(code hygiene)
- deliver
NormalizedCostRecordv2 — FOCUS 1.3-aligned schema covering all 77 Cost and Usage Dataset columns + 13 Contract Commitment Dataset columns (corrected from 11 — 2026-03-21) - map Phase 1
NormalizedCostRecordfields (amountType, allocationScope, providerRole, commitmentType) to FOCUS equivalents (chargeCategory, allocatedMethodID, serviceProviderName/hostProviderName, Contract Dataset) - validate
NormalizedCostRecordv2 against FOCUS Validator tool (focus.finops.org) upgrade✅ Done (2026-03-22) — Phase 8B billing FOCUS upgrade landed.billing.estimate.actualandbilling.compare.periodMCP tools to operate onNormalizedCostRecordv2billing.estimate.actualnow outputsrecords: NormalizedCostRecord[](FOCUS 1.3 v2, schemaVersion 2.0.0) with abillingPeriodSummaryToRecords()mapper in the tool layer;recordCountreplaceslineItemCount;records[n].serviceName(FOCUS ServiceName) replaceslineItems[n].service;records[n].skuIdreplacessku.billing.compare.periodupgraded:ServiceDelta.serviceName(FOCUS) replacesservice;focusSchemaVersion: "2.0.0"in output; Phase 10 NormalizedCostRecord[] pass-through branch added to both tools. Transport bumped to v0.11.0. 161/161 tests green (gap identified 2026-03-21, previously missing from plan)- deliver
@ficecal/integration-openopsadapter plugin — OpenOps export →NormalizedCostRecordv2 - deliver
@ficecal/integration-infracostadapter plugin — Infracost JSON →NormalizedCostRecordv2 - deliver
@ficecal/billing-openaiv2 — live OpenAI Usage API path (ingestMode: "live") - deliver
@ficecal/billing-awsv2 — live AWS Cost Explorer SDK path - deliver
@ficecal/billing-gcpv2 and@ficecal/billing-azurev2 — live provider SDK paths - implement Contract Commitment Dataset fixture + MCP tool (
billing.commitment.query) — 13 columns (corrected from 11) - implement Allocation columns (5) +
billing.chargeback.allocateMCP tool — enablesshared-cost-allocationscope content - activate
commitment-managementscope content — remove feature-flag guard added in Phase 7; wire to Contract Commitment Dataset +billing.commitment.query - activate
shared-cost-allocationscope content — wire to Allocation columns +billing.chargeback.allocate - deliver
duksh/ficecal-plugin-registryGitHub repo —index.json,ficecal-plugin.schema.json, CI validation workflow, CONTRIBUTING.md - deliver
packages/plugin-registry-client— fetchesindex.jsonfrom GitHub raw, validates sha256, caches with TTL - deliver
npx create-ficecal-pluginscaffold — boilerplate,ficecal-plugin.json, vitest harness, GitHub Actions publish + registry-PR workflow - deliver
ficecal-plugin-sdk— mock PluginHost, mock BillingRegistry, theme token validator, FocusValidator - deliver
executive-strategy-module— multi-year investment framing, leadership KPI narrative (Framework 2026 — Executive Strategy Alignment capability) - deliver
finops-assessment-module— crawl/walk/run maturity scoring against all 22 Framework 2026 capabilities - enrich
@ficecal/reference-evidenceEVIDENCE_CATALOG with per-capability FiceCal evidence entries cross-referencing section 4B matrices — makesqueryEvidence()return genuinely useful per-claim traceability rather than citing the spec document (gap identified 2026-03-21 — may be pulled into Phase 7 if capacity permits) - update section 4B Framework 2026 matrix status for
commitment-managementandshared-cost-allocationscope content after Phase 8 delivery
- implement plugin sandbox — Web Worker or Deno worker per plugin with resource limits → Carried to Phase 10 P5
- implement signed
ficecal-plugin.jsonmanifests — GPG or code-signing; reject unsigned community plugins → Carried to Phase 10 P6 - implement
ficecal-plugin-lock.json— version pinning for installed plugins → Carried to Phase 10 P6 - implement auto-update with changelog surfaced in admin panel → Carried to Phase 10 P7
- deliver
billing.anomaly.detectMCP tool — threshold-based spike detection; model-lens enrichment;AnomalyRecord[]with severity + projected overage - deliver
packages/billing-ai-providers—AiProviderBillingAdapterinterface +normalize.ts(tokens ×ModelPricingReference→NormalizedCostRecordv2) - deliver Anthropic usage-API adapter (direct API, not Bedrock)
- deliver OpenAI usage-API adapter (
/v1/usageby model) - deliver Gemini usage-API adapter (AI Studio + Vertex AI)
- deliver Mistral usage-API adapter
- deliver DeepSeek usage-API adapter
- deliver Alibaba (Qwen) usage-API adapter (CNY→USD via
StaticForexAdapter) - deliver
finops.assessment.correlateMCP tool —ingestMode: "contextual"; domain → service category mapping;totalAddressableWaste; ROI-rankedcorrelatedRecommendations - deliver
billing.routing.optimizeMCP tool — top-3 model substitution opportunities;estimatedMonthlySaving; sourced fromModelPricingReferencevs actual spend - implement plugin sandbox — Web Worker per plugin (Phase 9 P5 carryover)
- implement signed
ficecal-plugin.jsonmanifests (Phase 9 P6 carryover) - implement auto-update pipeline (Phase 9 P7 carryover)
- bump transport to v0.14.0 on Phase 10A completion
- defer
@ficecal/integration-openopsand@ficecal/integration-infracostto Phase 11
Note: the following governance gate issues were previously listed as a duplicate "Phase 7 issue set" block. Merged here (2026-03-21); the duplicate heading has been removed. These items are now consolidated in the Phase 7 issue set above.
- add release gates for framework-alignment evidence (now in Phase 7 issue set above)
- add release gates for FOCUS field mapping validation (now in Phase 7 issue set above)
- publish a spec/framework support checklist for every claimed alignment area (now in Phase 7 issue set above)
- block releases that make unsupported standards claims (now in Phase 7 issue set above)
establish GitOps branch structure (✅ Donedevelop,feature/*, CI guardrails)rename✅ Doneduksh/modelstoduksh/ficecal-model-lensimplement✅ Done — PR #118ModelPricingReferencecontract,duksh-models-adapter, snapshot versioning, benchmark gate (Gaps 2–4)Phase 0 baseline artifacts (Framework 2026 / FOCUS 1.3 assessment, parity declaration, feature-catalog update)✅ Done — PR #119✅ Donerelease/phase-0branch openedPhase 1:✅ Done —economics-modulecompute kerneldecimal.jswrapper,FormulaRegistry,StaticForexAdapter, period normalization; Gap 5 closedPhase 2: all 11 modules✅ Done — PRs #123–137; 352 tests;v2.0.0-phase-2-exittaggedGap 1 (image pricing unit) closed✅ Done — PR #125computeImageCostGap 5 (forex source) closed✅ Done —ForexRateProvider+StaticForexAdapterincore-economicsEconomics module umbrella ADR resolved✅ Done —@ficecal/economics-modulewithEconomicsPluginextension interface (PR #133)
| Deliverable | PR | Tests | Notes |
|---|---|---|---|
@ficecal/ui-foundation — types, preferences, theme, intent-scope, i18n, keyboard, telemetry |
#138 | 75 | Zero DOM deps; all browser APIs injectable |
apps/web — ThemeToggle, IntentScopeBar, useUiFoundation() hook |
#139 | — | TypeScript strict, zero errors |
feature-catalog.json v1.5.0 |
#139 | — | ui-foundation entry active; web.dependsOn updated |
v2.0.0-phase-3-exit tag |
— | — | Cut on develop 2026-03-21 |
- Monorepo cutover — migrate to full pnpm workspaces layout; absorb
ficecal-model-lensintoapps/model-lens/ apps/webproduction hardening — wire economics computations to IntentScopeState; Playwright evidence suitechart-presentationrender integration — wire D3 chart builders to health-score and economics-module outputs
| Deliverable | Tests | Notes |
|---|---|---|
packages/plugin-api — FicecalPlugin, PluginHost, ThemeRegistry, BillingRegistry |
25 | Zero-dependency; feature-flag guard; contribution routing |
| Billing fixture plugins × 4 (AWS / GCP / Azure / OpenAI) | 24 | Deterministic ingestMode; real Cost Explorer / GCP / Azure CM / OpenAI export shapes |
billing.estimate.actual + billing.compare.period MCP tools |
— | Registered in transport; wired via setBillingRegistry() |
Theme plugins × 4 in @ficecal/ui-foundation |
— | lightThemeContribution, darkThemeContribution, highContrastThemeContribution, oceanBlueThemeContribution |
v2.0.0-phase-6-exit tag |
— | Cut on develop 2026-03-21; 77 tests green |
- Wire
ThemeRegistry→ThemeManager— bootThemeRegistryfromBUILT_IN_THEMESat app startup; routeThemeManager.apply()through registry; live theme picker inapps/web - Hook/filter system (
HookRegistry) —addFilter/addActionAPI inpackages/plugin-api; at least one filter in production use (billing result post-processing or theme-change action) - Admin panel in
apps/web— plugin list, theme picker with swatches, billing provider status fromBillingRegistry.readyProviders - Workspace isolation (
WorkspaceRegistry) — scope plugins, themes, billing adapters perworkspaceId; required for hosted multi-tenant model - Governance release gates — economics fixture parity, invariant tests, chart parity, task-flow smoke tests, accessibility checks
- ECB live forex feed adapter (Phase 8 — integration module plugin)
- OpenOps / Infracost adapters and FOCUS-ready normalized cost records (Phase 8 — as plugins)
NormalizedCostRecordv1 full contract — commitment, allocation, recency/completeness semantics (Phase 8)- Live billing SDK integration (AWS Cost Explorer live mode — Phase 8)
- Plugin marketplace / registry client at
plugins.ficecal.com(Phase 8) - Developer SDK +
npx create-ficecal-pluginscaffolding (Phase 8) - Plugin sandbox (Web Worker isolation per plugin) (Phase 9)
- Signed plugin manifests +
ficecal-plugin.jsonstandard (Phase 9) - Auto-update pipeline for community plugins (Phase 9)
- framework-alignment evidence gates and FOCUS field mapping validation (Phase 7)
billing.anomaly.detect— P0; self-contained; highest practitioner value; does not depend on P1 adapters; ships firstpackages/billing-ai-providers+normalize.ts— foundation that all 6 provider adapters share; build interface before adapters- All 6 provider usage-API adapters — Anthropic, OpenAI, Gemini, Mistral, DeepSeek, Alibaba; each thin (usage API only); pricing from
ModelPricingReference finops.assessment.correlate— requires billing records from P2 adapters to be meaningful; build after at least 2 adapters are livebilling.routing.optimize— requires both correlation tool and multi-provider spend data; Phase 10A final deliverable- Phase 9 carryover (sandboxing/signing/auto-update) — Phase 10B; does not block Phase 10A intelligence layer
@ficecal/integration-openops— OpenOps export →NormalizedCostRecordv2@ficecal/integration-infracost— Infracost JSON →NormalizedCostRecordv2- Live GCP billing adapter (native Cloud Billing export, not usage API)
- Live Azure billing adapter (native Cost Management export)
billing.attribution.pr— engineer-facing PR cost delta (shift-left FinOps)executive-strategy-module— multi-year investment framing, leadership KPI narrative
FiceCal v2 should be implemented as a parity-preserving, contract-first modular evolution of the current live product, with the economics kernel, charting, health/recommendation logic, UI foundation, and scope-aware analytical framing stabilized before serious expansion into MCP services, monorepo-wide cutover, and direct billing adapters. Framework 2026 alignment should be pursued first through business-question and decision-support improvements, while FOCUS 1.3 alignment should be pursued later through explicit normalized data contracts, integration adapters, and evidence-backed support claims.
Scope: Close all 53 gaps identified in the post-Phase-10 gap register across 7 categories (F: FinOps Framework, S: FOCUS schema, A: AI technology, P: Plugin ecosystem, D: Data/oracle, U: UX, I: Integration).
- NormalizedCostRecord bumped to
v2.1.0(~93% FOCUS 1.3 coverage)- Added:
CapacityReservationId,CapacityReservationStatus,SkuMeter,SkuPriceDetails,PricingCurrencyContractedUnitPrice,PricingCurrencyEffectiveCost,PricingBlockSize,ServicePeriodStart,ServicePeriodEnd,BillingCurrency,EffectiveExchangeRate normalizeRecord()updated to set new fields; 99 schema tests green
- Added:
- ContractCommitmentRecord (FOCUS 1.3 Contract Commitment Dataset) — new type, 13 columns
CONTRACT_COMMITMENT_SCHEMA_VERSION = "1.0.0"exported
- Model catalog schema extended:
ImageModelPricingReference,GpuModelPricingReferencetypes addedModelPricingReferencegains:reasoningTier?,maxInputTokens?,maxOutputTokens?,trainingCutoff?
initializeCatalog()— async function inservices/mcp/src/transport/registry.ts- Calls
loadModelPricingCatalog()(HTTP oracle with 8s timeout → bundled fixture fallback) - Wires catalog into
setAiProviderPricingCatalog()andsetRoutingCatalog(buildRoutingCatalogFromPricing()) - Called in
buildApp()beforeregisterMcpRoutes()— catalog ready before first request
- Calls
- Catalog refresh worker —
setInterval(default 6h) with.unref()inserver.ts- Configurable via
MCP_CATALOG_REFRESH_INTERVAL_MSenv var
- Configurable via
per_gpu_houradded to@ficecal/ai-token-economics:- New
GpuCostInputinterface (gpuHours, gpuCount, pricePerGpuHour, workloadType, gpuType) computeGpuCost()function + dispatcher wiring- 15 GPU cost tests → 47 total ai-token-economics tests passing
- New
@ficecal/carbon-economics— new package (Phase 11)types.ts:RegionCarbonIntensity,WorkloadPowerProfile,CarbonEstimateInput/Outputcatalog.ts: 19 regional intensity entries (AWS×8, GCP×6, Azure×5); 6 workload power profilesengine.ts:estimateCarbon()— formula-based engine, PUE-aware, world-average fallback- 18 tests green on first run; package added to pnpm workspace
All 4 tools registered in services/mcp/src/transport/registry.ts. Tool count: 11 → 15.
| Tool ID | Capability | Phase | Tests |
|---|---|---|---|
sustainability.carbon.estimate |
FinOps 2026 Sustainability | 11 | ✓ |
billing.rate.optimize |
Rate Optimization (RI/SP/CUD) | 11 | ✓ |
billing.usage.optimize |
Usage Optimization (rightsizing) | 11 | ✓ |
billing.ai.quota |
AI Spend Quota Management | 11 | ✓ |
McpToolInputSchemaextended to support array/object property schemasMcpJsonSchemaPropertyinterface added (recursive)- 31 new Phase 11 tool tests → 63 total mcp-tooling tests passing
billing-compare-period.tsupdated to useNORMALIZED_COST_RECORD_SCHEMA_VERSIONconstant
PluginHostconstructor accepts optionalPluginSandboxparameter (3rd arg, default null)register()method now:- Calls
validatePluginManifest(plugin.manifest)when manifest is present →MANIFEST_INVALIDerror on failure - Fires
plugin.unverifiedhook for community plugins without manifest (backward-compatible) - Sandbox-wraps all
adapter.load()calls whenPluginSandboxis active
- Calls
FicecalPlugintype gains optionalmanifest?: FicecalPluginManifestPluginErrorCodeunion gains"MANIFEST_INVALID"- Health endpoint updated: phase 10→11, version 0.13.0→0.14.0
- Adds
pluginCount,plugins[](id, version, enabled, verified),sandboxstatus
- Adds
getPluginHost(),getWorkspaceRegistry()imported in routes.ts
| Package | Tests | Status |
|---|---|---|
| @ficecal/schemas | 99 | ✓ |
| @ficecal/plugin-api | 165 | ✓ |
| @ficecal/mcp-tooling | 63 | ✓ |
| @ficecal/service-mcp | 244 | ✓ |
| @ficecal/carbon-economics | 18 | ✓ |
| @ficecal/ai-token-economics | 47 | ✓ |
| @ficecal/billing-ai-providers | 102 | ✓ |
| All other packages | 515 | ✓ |
| TOTAL | 1,253 | ALL GREEN |
- UX (U1–U6): ArchitectPanel ↔ billing.routing.optimize, IntelligencePanel auto-trigger, IntentScopeBar scope degradation guards, AdminPanel Security tab — frontend work, no test coverage gate
- I1–I5: OpenOps/Infracost integration adapters, live GCP/Azure adapters, PR cost attribution
- A5: Live AI billing (Anthropic/OpenAI usage API SDK calls)
- F8:
billing.attribution.pr(engineer shift-left FinOps)
10 first-time visitor experience gaps (G1–G10) identified via live UX audit comparing localhost:4321 against duksh.github.io. Full gap register, resolution priority table, and sprint definition of done in §6A. This is a pure frontend sprint (Astro + Tailwind, no MCP/backend changes). Estimated effort: XS–M items, completable in 3–5 days.
- G1 (P1): Hero / value proposition above the table
- G2 (P2): Brand attribution correction
- G3 (P7): First-visit orientation callout
- G4 (P4): Cost-per-1M-tokens derived column
- G5 (P5): Empty cell tooltip
- G6 (P3): Use-case filter shortcut chips
- G7 (P6): Column header definitions / tooltips
- G8 (P9): Data-source attribution footer
- G9 (P8): Example query buttons
- G10 (P10): Responsive layout for mobile