Appearance
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:
- The project's own cost centre, when set.
- Otherwise → the
dormantCostCentrestashed 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, intactThis 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:
| Mode | Effect |
|---|---|
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 optionaljurisdictionCode(resolves from the org default when omitted — never silently hardcoded) and an optional R&DframeworkId. - 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.
- API:
adHocCapexClaimCreate. - An ad-hoc claim can be promoted to an Initiative-anchored one later via
capexClaimConvertToInitiative— useful once a one-off body of work grows into a funded 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):
| Field | Meaning |
|---|---|
forecastCost | Forecast cost from allocations across the Initiative's projects |
actualCost | Actual cost rolled up from effort |
costVariance | forecastCost − actualCost |
costVariancePct | Variance as a ratio (ungated — a ratio leaks no £) |
assignedFte / actualFte / fteVariance | The 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
- Initiatives — the conceptual model.
- API → Initiatives — types, queries, mutations, error codes.
- Cost Capitalisation — the per-project review surface that the claim evidence reuses.
- Variance Tracking — budget snapshots and cost-review workflow the variance feeds.