---
title: LFCS Pricing History
created: 2026-05-03
created_by: claude-code-coo (Phase-1 scaffolding ahead of Phase-2 ingest)
status: scaffolded-no-data
purpose: Cross-job pricing history. One markdown file per priced BOQ line. Greppable + Obsidian-searchable for MVP; SQLite-derived for v2 once ~50 jobs.
related:
  - "[[LFCS-Bid-System-Plan-2026-05-03]]"
  - "[[../element-taxonomy]]"
  - "[[../rate-card]]"
---

# LFCS Pricing History

> **Status: scaffolded, no data ingested yet.** Per LFCS Bid System plan, ingest is Phase 2 work — gated on (a) RateRight worker-supply hunt advancing OR (b) Phase 1 winning ≥2 bids. This README documents the schema so the scaffolding is ready when the gate opens.

## Purpose

Single source of truth for "what did LFCS price for X last time, and what did the QS land on." Drives:
- Faster bid pricing (lookup before estimating)
- Tighter estimates (history-weighted rates)
- The flywheel — every bid's QS-comparison feeds the next bid's lookup

## Layout

```
pricing-history/
├── README.md                                              ← this file
├── _Log.md                                                ← append-only ingest log
├── {job_no}-{boq_section}-{element-slug}.md               ← one file per priced BOQ line
└── _index/                                                ← (v2) sqlite-derived indices
```

Filename convention: `{job_no}-{boq_section}-{element-slug}.md`
Example: `2602-6.4.1-place-finish-concrete-abutment.md`

## Per-line schema (markdown frontmatter)

```yaml
---
job_no: 2602                          # 4-digit year-prefixed
client: Dec Projects
job_type: bridge-frp-package
boq_section: 6.4.1                    # verbatim from BOQ
description: Place + finish concrete — abutments  # verbatim from BOQ

# CONTROLLED VOCAB — must match element-taxonomy.md
element: place-finish-concrete
sub_element: abutment
material: concrete-50mpa

# QUANTITIES + RATES
unit: m3                              # m3, m2, m, T, kg, Item, Sum, LS, lf
quantity: 53.064                      # from boq-normalised.json
unit_rate_aud: 380                    # what LFCS priced
qs_unit_rate_aud: 365                 # what QS landed on (null if not shared)
qs_share_status: shared-verbal        # shared-verbal | shared-written | declined-to-share | not-asked
delta_pct: -3.95                      # auto-calc; null if qs_share_status != shared-*
cost_basis:                           # subby quotes feeding LFCS rate (optional)
  - subby: Boral Newcastle
    rate: 320
    date: 2026-05-04
  - subby: Holcim
    rate: 335
    date: 2026-05-04

# CONTEXT — drives lookup matching
date_priced: 2026-05-06
outcome: submitted                    # submitted | awarded | lost | withdrawn
location: NSW-Central-Coast           # state + region
shift: day                            # day | night | weekend
complexity_factors:                   # multi-tag from element-taxonomy.md
  - height-over-3m
  - salt-water-proximity
  - heavy-reo-density-over-200kgm3
  - nfc-drawings
notes: Heavy reo intensity (287 kg/m³). Saltwater proximity priced in.
source_job: "[[2602 - Dec Projects - Munmorah Bridge/00-Bid-Prep]]"
---

[free-text body — only if a non-obvious assumption drove the rate]
```

## Validation

`element` and `sub_element` MUST validate against `lfcs-standards/element-taxonomy.md`. The ingest skill (`lfcs-bid-vs-qs-compare`, Phase 2) rejects unknown values and prompts taxonomy update before proceeding. Don't bypass validation by editing files directly — taxonomy drift is the single biggest risk to this dataset.

## Anonymisation policy (default)

Per LFCS Bid System plan Open Decision (b)-7: until Rocky confirms otherwise with QS counterparties (Robert at Dec Projects in the first instance), `qs_unit_rate_aud` is captured but `client` field uses anonymised hash (`dec-projects-hash` rather than verbatim). Captured-by-name only after explicit OK on the Tuesday call.

## Lookup queries

### MVP (markdown + ripgrep / Obsidian dataview)

```bash
# Last 5 jobs with 200mm RC L-wall
rg -l "element: rc-l-wall" pricing-history/ \
  | xargs head -25 \
  | grep -E "^(job_no|sub_element|unit_rate_aud|qs_unit_rate_aud|date_priced|complexity_factors)" \
  | ...
```

```dataview
TABLE unit_rate_aud, qs_unit_rate_aud, date_priced, complexity_factors
FROM "11_OpsMan_LFCS/Operations/lfcs-standards/pricing-history"
WHERE element = "rc-l-wall" AND contains(sub_element, "200mm")
SORT date_priced DESC
LIMIT 5
```

### v2 (SQLite — generated from frontmatter via sync script)

```sql
SELECT job_no, sub_element, unit_rate_aud, qs_unit_rate_aud, date_priced
FROM lines
WHERE element = 'rc-l-wall' AND sub_element LIKE '%200mm%'
ORDER BY date_priced DESC
LIMIT 5;

-- aggregates with complexity_factors
SELECT AVG(unit_rate_aud) AS avg_rate, COUNT(*) AS n
FROM lines
WHERE element = 'place-finish-concrete'
  AND sub_element = 'abutment'
  AND complexity_factors LIKE '%salt-water%'
  AND date_priced > '2026-01-01';
```

## Phase-2 ingest workflow (will run via lfcs-bid-vs-qs-compare)

1. Bid submitted → `lfcs-bid-vs-qs-compare` reads `priced-boq.md` + Tuesday-call notes (with QS-shared rates).
2. Per BOQ line: build line file using schema above.
3. Validate `element` + `sub_element` + `complexity_factors` against `element-taxonomy.md`. Reject if drift.
4. Write file to `pricing-history/{job_no}-{boq_section}-{slug}.md`.
5. Append to `_Log.md`: `- {date} {time} — claude-code-coo via lfcs-bid-vs-qs-compare — {job_no} — {n} lines ingested`.
6. (v2) Trigger SQLite sync.

## Backfill plan (optional, Phase 2)

If Rocky has 3-5 priced BOQs from past LFCS jobs, manually backfill (~2hr/job). Critical for the flywheel to have signal on day one. Skip if not available — the system bootstraps from new bids onward.

## Maintenance

Per skill catalog README: 30-min monthly audit. For pricing-history specifically:
- Re-validate every line against current `element-taxonomy.md` (in case taxonomy renamed an alias).
- Spot-check 5 random lines for schema completeness.
- Confirm QS-share anonymisation policy still aligned with Rocky's confidentiality posture.
