1. Purpose
An Adjudication is a persistent comparison object that imports competing supplier/subcontractor prices, normalises them for like-for-like comparison, and on award updates the Estimate with the winning pricing. Two structurally identical flavours exist — differing only in scope and output.
- Price Book Adjudication: scopes over Resources selected from the Estimate. Supports multiple rounds. On award, winning rates replace the existing Resources (BR-062).
- Subcontract Package Adjudication: scopes over an Item bundle. Supports multiple rounds. On award, creates/updates a system-generated Price Book with Subcontract Resources (BR-063).
Both follow the shared six-step workflow (BR-068): Generate → Export → Import → Compare → Normalise → Transfer.
2. Attributes
Shared (both flavours)
| Attribute | Type | Required | Default | Notes |
|---|---|---|---|---|
id | UUID | ✅ | generated | System-managed |
name | string | ✅ | — | E.g., “Labour rates Q2 2026” or “Electrical subcontract round 1” |
status | enum | ✅ | Draft | Draft · Adjudicated. See §5 |
created_at / updated_at | timestamp | ✅ | system | Audit |
created_by / updated_by | User ref | ✅ | system | Audit |
Price Book Adjudication specific
| Attribute | Type | Required | Default | Notes |
|---|---|---|---|---|
adjudication_type | enum | ✅ | — | Discriminator: price_book |
estimate_id | Estimate ref | ✅ | — | Parent Estimate (M:1) |
scoped_resource_ids | array of UUID | ✅ | [] | Resources being adjudicated (M:M join) |
round_number | integer | ✅ | 1 | Sequential round within the same resource set (BR-062) |
Subcontract Package Adjudication specific
| Attribute | Type | Required | Default | Notes |
|---|---|---|---|---|
adjudication_type | enum | ✅ | — | Discriminator: subcontract_package |
estimate_id | Estimate ref | ✅ | — | Parent Estimate (M:1) |
subcontract_package_id | Subcontract Package ref | ✅ | — | Package being adjudicated (M:1) |
round_number | integer | ✅ | 1 | Sequential round within the Package (BR-065) |
system_generated_price_book_id | Price Book ref | ❌ | null | Produced on award; system-generated (BR-063). Null until Adjudicated status |
3. Supplier/Subcontractor Returns (M:M join)
Both flavours track competing returns via a join table: Adjudication Return (one per participating Company).
| Attribute | Type | Notes |
|---|---|---|
id | UUID | Return record ID |
adjudication_id | UUID ref | Parent Adjudication |
company_id | Company ref | Supplier or Subcontractor (Company Role validated) |
return_received_date | timestamp | When this return was imported |
return_data (JSON) | object | Priced line items: [{ item_id, resource_id, quoted_rate, unit, notes }, ...] (Price Book Adj) or [{ item_id, quoted_rate, variances: {...} }, ...] (Subcontract Adj) |
selected | boolean | True if this return’s pricing was awarded (BR-068 Transfer step) |
awarded_at | timestamp | When selection occurred |
4. The Six-Step Workflow (BR-068, shared for both flavours)
Step 1: Generate
Purpose: Assemble the comparison package.
- Price Book Adjudication: Estimator selects Resources from the Estimate’s active Price Books (e.g., 8 labour rates across 3 suppliers). System creates a scoped list with current rates as baseline.
- Subcontract Package Adjudication: Estimator references the Subcontract Package (pre-existing; persistent). System snapshots the Package’s Items (names, quantities, units) as the scope.
Stored: scoped_resource_ids (PBA) or subcontract_package_id (SPA). Status = Draft.
Step 2: Export/Send
Purpose: Package the scope for distribution to competing suppliers.
- Format: Excel or PDF with:
- Baseline rates (PBA: current Resource rates; SPA: item descriptions, quantities, units)
- Instructions for return (add your quoted rates)
- Variances template (optional inclusions, exclusions, cost notes)
- Distribution: manual email or system integration (future; out of scope v1)
- Tracking:
return_received_dateon each Return once imported
Step 3: Import
Purpose: Ingest competing returns.
For each supplier:
- Estimator uploads an Excel return file via Import Wizard.
- Import Wizard: smart column mapping (auto-detect or manual override), preview validation, error detection.
- System parses and stores in the Return record (
return_dataJSON). - Validation: quantities match scope; units align; rates are numeric.
Stored: Return records in adjudication_return join table.
Step 4: Compare
Purpose: Side-by-side view of competing quotes with variances.
- Display: table or card view showing baseline vs each supplier’s return, +/- variance per item.
- Variance logic: if supplier says “includes waste factor” but baseline doesn’t, estimator marks as +$X (inclusion). System tracks these notes.
- Variance/inclusion notes: captured as Content Block instances on the affected Item Worksheets. Notes persist on Items after award, independent of the Adjudication.
- No change to data: this is a read-only exploration step.
Step 5: Normalise (BR-068a)
Purpose: Add missed items for like-for-like comparison.
- If Supplier A quoted everything but Supplier B omitted one rate, estimator can add a normalisation row to B’s return (e.g., “use Supplier A’s rate for that item, or a manual estimate”).
- Critical: Normalisation items exist transiently in the Adjudication only. They are not written back to the Estimate’s Resources or Items.
- Usage: only the selected winner’s pricing (including any normalisations that apply to them) is transferred on award.
Stored: Normalisation rows live in the Adjudication’s comparison state, not persisted to Resources.
Step 6: Transfer to Buildup (BR-068)
Purpose: Apply the award.
-
Price Book Adjudication (BR-062):
- Estimator selects one Supplier’s return.
- System updates the scoped Resources: replaces
ratewith the awarded supplier’s quoted rates. - Estimate immediately reflects the new rates.
- Workflow complete: Adjudication status = Adjudicated. Resources updated in place.
-
Subcontract Package Adjudication (BR-063):
- Estimator selects one Subcontractor’s return.
- System creates or updates the system-generated Price Book (one per Package, reused across rounds).
- For each Item in the Package, creates a Subcontract Resource with the awarded rate.
- Each Item’s Worksheet gets a Worksheet Resource linking to its corresponding Resource.
- Workflow complete: Adjudication status = Adjudicated. System-generated Price Book populated. Items now reference the awarded Resources.
5. Lifecycle States
| State | Meaning | Who can transition |
|---|---|---|
| Draft | Initial state. Scope assembled, returns imported, under comparison/normalisation | Estimator, Lead Estimator, Admin |
| Adjudicated | Award applied. Resources updated (PBA) or system-generated Price Book created (SPA) | Automatic on Transfer step completion |
State transitions:
Draft ──normalise & transfer──> Adjudicated
Adjudicated ──re-open──> Draft (BR-064; constrained by Estimate state)
Re-open constraints (BR-064): Adjudications can be re-opened (Adjudicated → Draft) only while the parent Estimate is in an editable state (In Progress / Reviewed). Once the Estimate transitions to Submitted (or beyond — Won / Lost / Archived), the Estimate is locked (BR-094) and its Adjudications are frozen.
Re-open semantics (BR-067): When Adjudicated → Draft, the Resources persist unchanged in the system-generated Price Book (SPA) or remain updated in the Resources (PBA). Re-opening does not undo the award; it allows a new round of adjudication. For SPA, the same system-generated Price Book is carried forward and updated on the next award.
6. Relationships
Inbound (things referring to Adjudication)
| From | Cardinality | Notes |
|---|---|---|
| Estimate | Adjudication M:1 Estimate | Both flavours belong to one Estimate |
| Subcontract Package | SP 1:M SPA Adjudication | Only SPA; one Package can have multiple rounds (BR-065) |
| Price Book (system-generated) | PB 1:0..1 SPA | Lineage is 1-to-1: each SPA produces at most one system-generated Price Book, and each system-generated Price Book points back to exactly one SPA |
Outbound (things Adjudication references)
Price Book Adjudication:
| To | Cardinality | Required | Notes |
|---|---|---|---|
| Estimate | PBA M:1 Estimate | ✅ | Parent |
| Resource | PBA M:M Resource | ✅ | Scope (selected for adjudication) |
| Company (Supplier) | PBA M:M Company | ✅ | Via Adjudication Return (competing suppliers) |
Subcontract Package Adjudication:
| To | Cardinality | Required | Notes |
|---|---|---|---|
| Estimate | SPA M:1 Estimate | ✅ | Parent |
| Subcontract Package | SPA M:1 SP | ✅ | Package being adjudicated (M:1 per round) |
| Company (Subcontractor) | SPA M:M Company | ✅ | Via Adjudication Return (competing subs) |
| Price Book (system-generated) | SPA 1:0..1 PB | ❌ | Output of award; null until Adjudicated (BR-063) |
7. Validation / Invariants
Rules that must hold at all times:
- Adjudication belongs to one Estimate.
estimate_idcannot be null. - Status enum.
statusmust be Draft or Adjudicated. - Price Book Adjudication scope required. If
adjudication_type = price_book,scoped_resource_idsmust be non-empty. - Subcontract Package Adjudication scope required. If
adjudication_type = subcontract_package,subcontract_package_idmust be non-null. - Round number increments. For both PBA and SPA,
round_numbermust be sequential starting at 1 (enforced on create). - System-generated Price Book on SPA award. After Transfer step on SPA,
system_generated_price_book_idmust be non-null andstatus = Adjudicated. - Supplier/Subcontractor role enforcement at first gate (BR-069). Companies in Adjudication Returns must have the appropriate Role (Supplier for PBA; Subcontractor for SPA). Validation occurs at whichever comes first: adding the Company to the Adjudication, or importing the Company’s priced return.
- Return data consistency. Return JSON structures must match the adjudication type (scoped resource format for PBA; item format for SPA).
- No circular lineage. System-generated Price Books must not reference themselves.
- Re-open constraint. Adjudications locked in Adjudicated state cannot be re-opened if the parent Estimate is Submitted or beyond (BR-064).
- Item-membership freeze on SPA (BR-065). For Subcontract Package Adjudications: Items in the parent Subcontract Package can be added or removed while the current round is in Draft. Once the round transitions to Adjudicated, the Package’s Item set is frozen until the Adjudication is re-opened (creating a new Draft round).
8. Derived / Computed Attributes
| Attribute | Derivation | Notes |
|---|---|---|
current_status_label | Human-friendly status | ”Draft” or “Adjudicated” + awarded supplier/subcontractor name if applicable |
is_awarded | status == Adjudicated | Boolean convenience flag |
winning_company_id | From Return where selected = true | Null if Draft; populated on award |
is_re-openable | status == Adjudicated AND parent Estimate is in editable state (In Progress / Reviewed) | Per BR-064: re-open is gated on Estimate state in v1. Once the Estimate transitions to Submitted (or Won / Lost / Archived), Adjudications are frozen and this is false |
9. Revised attributes: round_number for PBA
Both Price Book Adjudication and Subcontract Package Adjudication now track round_number to support multiple rounds. For PBA, round_number increments when the same resource set is re-adjudicated (e.g., after a market re-check or cost review). This mirrors SPA’s existing round semantics and provides consistency across both flavours.
10. Worked Examples
Example 1 — Price Book Adjudication (8 labour rates, 3 suppliers)
Context: Estimate for office fitout. Estimator has baseline rates for Carpenters, Electricians, Plumbers (2–3 variants each = 8 total Resources) sourced from an old Price Book. Decides to seek fresh quotes.
Generate: Adjudication created; 8 Resources (all Labour type) selected as scope.
Export: Excel sent to 3 labour-hire suppliers (A, B, C) showing baseline rates, asking for updated day rates.
Import:
- Supplier A returns: all 8 rates, slightly above baseline (5–10% uplift)
- Supplier B returns: 7 rates (missed one Electrician variant); lower overall (3–8% discount)
- Supplier C returns: all 8 rates, highly competitive (10–15% discount on most)
Compare: Side-by-side table shows each supplier’s quote vs baseline. Estimator notes:
- B’s missing Electrician (variant 3) — a gap
- C is cheapest but markup language on “liability” differs from A & B
Normalise: Estimator adds normalisation row to B: “Use A’s Electrician variant 3 rate for B’s comparison” ($65/day). Now all three are directly comparable.
Transfer: Estimator selects Supplier C (best value despite markup language; risk accepted). System replaces the 8 Resource rates in the Estimate with C’s quoted rates:
- Carpenter day rate: $78 → $68
- Electrician day rate: $92 → $79
- Plumber day rate: $85 → $72
- (etc., all 8)
Result: Estimate immediately recalculates with lower labour costs. Adjudication status = Adjudicated. Adjudication remains attached to Estimate for audit trail and re-opening.
Example 2 — Subcontract Package Adjudication (electrical, 3 subs, creates system-generated Price Book)
Context: Estimate for construction project. Estimator groups electrical Items (12 items: panel install, wiring, testing, etc., totalling ~2800 labour hours) into a “Electrical subcontract” Package for pricing.
Generate: Adjudication created for the Electrical Package. Scope = 12 Items (descriptions, quantities, units captured as baseline).
Export: PDF/Excel sent to 3 electrical subcontractors showing 12 line items; each sub to quote a total or per-item rates.
Import:
- Sub A (ABC Electric): quotes fixed price per item (rates vary by item complexity)
- Sub B (XYZ Electrical): quotes a lump sum for the whole package ($285,000) + notes on variations
- Sub C (Local Sparks): quotes unit rates ($/hour) per item type
Compare: Estimator reviews returns. Sub B’s lump sum needs decomposition to compare fairly.
Normalise: Estimator decomposes B’s lump sum across the 12 items proportionally, adding normalisation notes. Now C’s hourly rates and A’s item rates are both visible in the comparison.
Transfer: Estimator selects Sub A (best value after normalisation, clear item breakdown, local). System:
- Creates a system-generated Price Book (e.g., “SPA Adjudication #42 — Electrical Round 1”, hidden from default list)
- Creates 12 Subcontract Resources (one per Item), each with Sub A’s quoted rate:
- Resource “Panel install” (Type: Subcontract): $12,500 LS
- Resource “Wall wiring 100m” (Type: Subcontract): $3.50/m
- (etc., one per Item in the Package)
- For each Item in the Package, creates a Worksheet Resource linking to its corresponding Resource in the system-generated Price Book
Result:
- Adjudication status = Adjudicated
- System-generated Price Book contains 12 Subcontract Resources (Sub A rates)
- Estimate’s 12 Items now pull their costs from this Price Book
- Lineage: estimator can trace each cost back to the adjudication that awarded it
Example 3 — Re-open after scope change (Subcontract Package Adjudication)
Context: Continuing from Example 2. One week after awarding to Sub A, the client changes scope: adds 2 new electrical items, removes 1 item. Estimator must re-adjudicate.
Before re-open:
- Adjudication #42 status = Adjudicated
- System-generated Price Book contains 12 Resources (A’s rates)
- Items 1–12 reference these Resources
Re-open: Estimator clicks “Re-open Adjudication #42”. Status reverts to Draft. The system-generated Price Book is preserved (BR-067): all 12 Resources remain with Sub A’s awarded rates. New Items (13, 14) and the removed Item (say #7) are scoped for re-adjudication.
New Generate: Adjudication now scopes over:
- Keep: Items 1–6, 8–12 (existing scope)
- Add: Items 13, 14 (new scope)
- Remove: Item 7 (marked out-of-scope)
Re-export, Re-import, Re-compare, Re-normalise, Re-transfer: Estimator repeats the workflow with 3 subs (or same Sub A + others). Selects winner (assume Sub A again).
On re-transfer: System updates the system-generated Price Book in place (BR-063, “creates or updates”):
- Items 1–6, 8–12: Resources remain unchanged (Sub A’s original rates)
- Items 13, 14: new Resources created with the re-adjudicated rates
- Item 7: Resource remains but is no longer referenced (orphaned or marked inactive in the Price Book)
Result: Estimate’s cost now reflects scope change + new adjudication. Audit trail shows two rounds: original award to A (12 items), then re-award after scope change (adds 2, retains 11 of original). No loss of history.