Skip to content

Initiative finance

The Initiative is where finance reads a group of projects: effort, forecast, variance and planned commitment all roll up from its children. It is not where finance is configured — the cost centre lives on the project. This page is the finance-side mechanic: how a project's cost centre resolves, how CapEx/R&D claims anchor and avoid double-counting, and how variance rolls up.

For the conceptual model — the Initiative/Project split, the inert gate, Finance Mode, the OKR tree — start with Initiatives.

Cost-centre resolution

The cost centre is a project concept. An Initiative is a reporting bucket with no cost centre of its own, so resolution never consults it:

  1. The project's own cost centre, when set.
  2. Otherwise → the dormantCostCentre stashed when the project was adopted (see below).

capitalisable is derived from the category of that resolved cost centre — a capex-category centre enables CapEx and R&D. It is not derived from the Finance Mode; see Finance Mode does billing only.

Superseded

Earlier releases resolved the cost centre through an Initiative-first chain, where the parent Initiative's centre won and the project's own was only a fallback. That is no longer the case, and Initiatives no longer carry a cost centre. The 2026-06-22 entry in the changelog records the change.

Dormant-on-adopt

When you adopt a project into an Initiative, the project's own cost centre is not discarded — it is stashed:

adopt:   LiveProject.costCentreId ──► LiveProject.dormantCostCentreId
         LiveProject.costCentreId  := null
         LiveProject.initiativeId  := <initiative>
         → the stashed centre still governs (resolution falls through to it)

detach:  LiveProject.costCentreId  := LiveProject.dormantCostCentreId
         LiveProject.dormantCostCentreId := null
         LiveProject.initiativeId  := null
         → the project's own cost centre is restored, intact

This makes adoption reversible and lossless. Detach an Initiative-adopted project and it falls back to exactly the cost centre it had before — no re-keying, no lost binding. The mechanic is enforced server-side in adoptProjectIntoInitiative / detachProjectFromInitiative; the API surface is initiativeAdoptProject / initiativeDetachProject.

Finance Mode does billing only

The Finance Mode on an Initiative governs billing visibility and nothing else:

ModeEffect
CLIENT_BILLING (Customer billed)Unlocks the SOW budgetedCost + target marginPct
INTERNAL_COST (Internal)Hides them

CapEx/R&D eligibility is independent of the mode — a Customer-billed Initiative sitting on a CapEx-category cost centre can still capitalise and claim.

CAPEX_RD_CLAIM is legacy

CAPEX_RD_CLAIM is retained only because Postgres enum values cannot be dropped safely. Every row was data-migrated to INTERNAL_COST and the value is never written again. Do not branch on it.

One parent only

A project can be adopted by at most one Initiative. Adopting a project that already has a parent throws PROJECT_ALREADY_ADOPTED (with the current parent's id in extensions.currentInitiativeId). Detach it first, or adopt into the Initiative you actually want.

The inert consequence

A synced project with no cost centre and no Initiative is inert — it contributes nothing to CapEx or the forecast. This is deliberate: a PMS sync cannot silently inflate your capitalised spend. Finance only books what a human anchored, either by assigning a cost centre or by adopting into an Initiative.

CapEx / R&D claims

Claims in the Initiative model are pull-based and anchored, replacing the per-project-only flow. A CapexClaim is a header — a reporting period, a jurisdiction, a status — and its CapexClaimProject rows are the evidence set (one per project). Per child project, Flowstate reuses the existing capitalisation machinery (the ProjectCapitalisation scaffold, project evidence, and AI-drafted rationale) — it never re-implements evidence or rationale.

There are two ways to raise a claim:

Initiative-anchored claim

Anchor a claim at an Initiative and Flowstate auto-pulls its child projects as the evidence set.

  • Valid when the Initiative is CapEx-eligible — that is, when at least one child project's resolved cost centre is capex-category. Eligibility is derived, not stored, and does not depend on the Finance Mode.
  • The period is { periodStart, periodEnd, claimPeriodKey } plus an optional jurisdictionCode (resolves from the org default when omitted — never silently hardcoded) and an optional R&D frameworkId.
  • API: initiativeCapexClaimCreate.

Ad-hoc claim

Raise a claim over a hand-picked set of projects with no Initiative anchor — for the long tail that does not warrant an Initiative.

The double-count guard

The cardinal rule: one claim per project per period. A project may appear in only one non-rejected claim for a given claimPeriodKey — the normalised period key (e.g. a fiscal-year code) is the double-count axis.

When you try to add a project that is already claimed for that period, the claim creation throws PROJECT_ALREADY_CLAIMED. The error carries the conflicting claim in extensions so the UI can deep-link straight to it:

json
{
  "message": "Project already claimed for this period",
  "extensions": {
    "code": "PROJECT_ALREADY_CLAIMED",
    "conflictingClaimId": "clx_claim_id",
    "liveProjectId": "clx_proj_id"
  }
}

A rejected claim releases its projects — they become claimable again for that period. This applies identically to Initiative-anchored and ad-hoc claims, so an Initiative claim and an ad-hoc claim can never quietly capitalise the same project twice.

Permissions

The whole CapEx-claim surface — capexClaims, capexClaim, and all three create/convert mutations — requires FINANCIALS_VIEW_SUMMARY. Initiatives themselves are readable with ROADMAP_INITIATIVES_VIEW; money fields on them are gated by FINANCIALS_VIEW_SUMMARY and zero out without it.

Variance — the headline

Because planned commitment lives on the Initiative and actuals roll up from its projects, forecast-vs-actual variance is the headline finance metric for an Initiative. It is exposed as Initiative.varianceSummary(startDate, endDate):

FieldMeaning
forecastCostForecast cost from allocations across the Initiative's projects
actualCostActual cost rolled up from effort
costVarianceforecastCost − actualCost
costVariancePctVariance as a ratio (ungated — a ratio leaks no £)
assignedFte / actualFte / fteVarianceThe same comparison in FTE

Alongside it, four supporting rollups drill into each side: plannedCommitment (committed FTE + AI budget), forecast (assigned FTE + forecast cost), effortActuals (actual FTE + cost), and aiSpend (AI cost from telemetry sessions stamped with the Initiative). All money fields are gated behind FINANCIALS_VIEW_SUMMARY; FTE and counts are always visible. See API → Initiatives → Rollups.

For client-billing Initiatives, the same variance read still applies, but you read it against budgetedCost and marginPct — billed-vs-budgeted rather than forecast-vs-capitalised.

Operating-model settings

The nouns and finance terms are workspace-configurable at Settings → Resourcing → Operating Model:

  • Terminology — relabel Initiative / Objective / Project and the capitalisation terms (entityTerminology).
  • Preset — pick an archetype (operatingModelPreset) that seeds defaults — e.g. an internal product company (CapEx/R&D-first) vs an agency (client-billing-first).

This drives the visible labels only; the finance model underneath is the same. The change is applied through organizationOperatingModelUpdate, gated by SETTINGS_ENTITY_CONFIG_UPDATE.

Where to go next

Flowstate Documentation