Building a ROM (Rough Order of Magnitude) Priority Score for Project Intake
Use case: You're running a project intake or pipeline board and want to collect ROM-level business case data from project submitters, then automatically calculate a priority score to help your PMO triage and rank incoming proposals.
What you'll learn
In this article we'll walk through:
What ROM data to capture and which property types to use
How to set up the custom properties on your pipeline board
How to write an Expression that calculates an overall ROM Priority Score
How to band that score into actionable priority categories
Tips for keeping your pipeline data clean and consistent
1. What are the building blocks of a ROM pipeline board?
A ROM (Rough Order of Magnitude) estimate is an early-stage approximation — typically ±25–50% accuracy — used to compare and rank project proposals before a detailed business case is developed.
To build a useful ROM scoring model in Fluid you need three things:
Building Block | Purpose |
|---|---|
Input Properties | Capture the raw ROM data from submitters (cost, benefit, alignment, etc.) |
A Calculated Expression | Combine inputs into a single numeric ROM Priority Score |
A Banding Expression | Translate the numeric score into a human-readable priority band |
💡 Tip: All of the custom properties below are created in Administration Console → Data Administration → Custom Properties against the relevant entity (e.g., Project or Board Item). See Setting up Custom Properties for a refresher.
2. Setting up your input properties
Create the following custom properties. We've grouped them by category to keep your submission form organised.
A. Strategic Alignment
Property Name | Data Type | Configuration |
|---|---|---|
Strategic Alignment | Valued Option |
|
Using a Valued Option means each selection carries a numeric value you can reference directly in expressions — no extra mapping needed.
B. Financial Estimates
Property Name | Data Type | Notes |
|---|---|---|
ROM Cost Estimate | Number (Currency) | Total estimated cost in your base currency |
ROM Annual Benefit | Number (Currency) | Estimated annual financial return or savings |
ROM Payback Period | Number | Months to recover investment |
Funding Status | Option |
|
C. Effort & Complexity
Property Name | Data Type | Configuration |
|---|---|---|
ROM Duration | Number | Estimated delivery duration in months |
ROM Effort | Number | Estimated total effort in person-days |
Complexity | Valued Option |
|
Technical Risk | Valued Option |
|
⚠️ Notice that Complexity and Technical Risk are scored inversely — lower complexity = higher score — because lower complexity is more favourable for feasibility.
D. Business Impact
Property Name | Data Type | Configuration |
|---|---|---|
Business Urgency | Valued Option |
|
Impact Scope | Valued Option |
|
Customer Impact | Valued Option |
|
Regulatory / Compliance | Yes/No | Is this required for regulatory or compliance reasons? |
E. Readiness & Confidence
Property Name | Data Type | Configuration |
|---|---|---|
Resource Availability | Valued Option |
|
ROM Confidence Level | Valued Option |
|
Sponsor Confirmed | Yes/No | Has an executive sponsor been identified? |
Key Dependencies | Text | Free-text — major dependencies or blockers |
3. Writing the ROM Priority Expression
Now for the fun part. Create a new Number custom property called ROM Priority Score and set its value using a Dynamic Logic Expression.
The model uses five weighted dimensions:
Dimension | Weight | What it measures |
|---|---|---|
Strategic Alignment | 30% | Fit with organisational strategy |
Financial Return | 25% | ROI based on ROM cost vs. benefit |
Business Impact | 25% | Urgency, scope, and customer effect |
Feasibility | 15% | Complexity, risk, resources, confidence |
Compliance Bonus | 5% | Regulatory obligation uplift |
The full expression
Code
(COALESCE([_StrategicAlignment-Value], 0) * 0.30)
+
(
IF(COALESCE([_ROMCostEstimate], 0) = 0 AND COALESCE([_ROMAnnualBenefit], 0) = 0, 50,
IF(COALESCE([_ROMCostEstimate], 0) = 0 AND COALESCE([_ROMAnnualBenefit], 0) > 0, 100,
IF(COALESCE([_ROMAnnualBenefit], 0) / IF(COALESCE([_ROMCostEstimate], 0) = 0, 1, COALESCE([_ROMCostEstimate], 0)) >= 3, 100,
IF(COALESCE([_ROMAnnualBenefit], 0) / IF(COALESCE([_ROMCostEstimate], 0) = 0, 1, COALESCE([_ROMCostEstimate], 0)) >= 2, 80,
IF(COALESCE([_ROMAnnualBenefit], 0) / IF(COALESCE([_ROMCostEstimate], 0) = 0, 1, COALESCE([_ROMCostEstimate], 0)) >= 1, 60,
IF(COALESCE([_ROMAnnualBenefit], 0) / IF(COALESCE([_ROMCostEstimate], 0) = 0, 1, COALESCE([_ROMCostEstimate], 0)) >= 0.5, 40,
20
)
)
)
)
)
)
* 0.25)
+
(
(COALESCE([_BusinessUrgency-Value], 0) * 0.40
+ COALESCE([_ImpactScope-Value], 0) * 0.35
+ COALESCE([_CustomerImpact-Value], 0) * 0.25)
* 0.25)
+
(
(COALESCE([_Complexity-Value], 0) * 0.35
+ COALESCE([_TechnicalRisk-Value], 0) * 0.25
+ COALESCE([_ResourceAvailability-Value], 0) * 0.25
+ COALESCE([_ROMConfidenceLevel-Value], 0) * 0.15)
* 0.15)
+
(IF([_RegulatoryCompliance] = true, 100, 0) * 0.05)
💡 Why COALESCE? During early intake, submitters may leave fields blank. Wrapping every field reference in
COALESCE([_Field], 0)ensures the expression evaluates safely instead of returning an error. See Dynamic Logic Expressions for more on safe expression patterns.
💡 Why the nested IF on cost? We guard against division by zero by checking
IF(COALESCE([_ROMCostEstimate], 0) = 0, 1, ...)before dividing. This is the same pattern recommended in the RICE/WSJF prioritisation article.
4. Banding the score into priority categories
Create a second custom property called ROM Priority Band (type: Text or Option, driven by expression) with this expression:
Code
CASE(
[_ROMPriorityScore] >= 80, "🔴 Must Do",
[_ROMPriorityScore] >= 60, "🟠 Should Do",
[_ROMPriorityScore] >= 40, "🟡 Could Do",
[_ROMPriorityScore] >= 20, "🔵 Watch",
"⚪ Deprioritise"
)
Score Range | Band | Recommended Action |
|---|---|---|
80 – 100 | 🔴 Must Do | Fast-track to detailed business case |
60 – 79 | 🟠 Should Do | Proceed to business case with standard review |
40 – 59 | 🟡 Could Do | Park for next planning cycle or refine the ROM |
20 – 39 | 🔵 Watch | Monitor — revisit when conditions change |
0 – 19 | ⚪ Deprioritise | Decline or defer indefinitely |
5. Worked example
Let's say a project called "Customer Portal Modernisation" is submitted with:
Property | Value |
|---|---|
Strategic Alignment | High (75) |
ROM Cost Estimate | $500,000 |
ROM Annual Benefit | $800,000 |
Business Urgency | Near-term (75) |
Impact Scope | Enterprise-wide (100) |
Customer Impact | Direct – External (100) |
Complexity | High (40) |
Technical Risk | Medium (60) |
Resource Availability | Partially Available (65) |
ROM Confidence Level | Medium (60) |
Regulatory / Compliance | No |
Step-by-step calculation:
Dimension | Calculation | Result |
|---|---|---|
Strategic Alignment | 75 × 0.30 | 22.50 |
Financial (ROI = $800K/$500K = 1.6 → band = 60) | 60 × 0.25 | 15.00 |
Business Impact | (75×0.40 + 100×0.35 + 100×0.25) = 90 → 90 × 0.25 | 22.50 |
Feasibility | (40×0.35 + 60×0.25 + 65×0.25 + 60×0.15) = 54.25 → 54.25 × 0.15 | 8.14 |
Compliance Bonus | 0 × 0.05 | 0.00 |
ROM Priority Score | 68.14 |
Result: 🟠 Should Do — proceed to full business case with standard governance review.
6. Tips for keeping your pipeline clean
Tip | Why it matters |
|---|---|
Make Strategic Alignment and ROM Cost/Benefit mandatory | These carry the most weight — missing values will skew priorities |
Use the ROM Confidence Level honestly | A "Low" confidence ROM shouldn't outrank a "High" confidence one at the same score |
Review weights quarterly | As organisational priorities shift, adjust the dimension weights (the 0.30/0.25/0.25/0.15/0.05 split) to match |
Don't over-engineer early | ROM is meant to be rough. Resist adding more properties until you've validated the model over one or two intake cycles |
Combine with board views | Use Fluid's board grouping or filtering to create a "Pipeline by Priority Band" view so stakeholders see a clean ranked backlog |
Set Sponsor Confirmed as a gate | Consider making progression from 🟠 Should Do → detailed business case contingent on |
