---
name: lfo-rfi-extract
description: Invoke after Phase 3 step 3 (bid-prep) OR Rocky-typed "process RFIs" / "extract RFIs from worker output". Reads worker output for RFI candidates (drawings note "Refer to xxx", missing drawings flagged in drawing index, scope ambiguities, undefined supply splits, programme gaps, technical clarifications). Captures into structured RFI register at `06 - Correspondence/06b - RFIs/RFI-Register-{job_no}.md` — append-only. Prioritises by impact (HIGH / MEDIUM / LOW). Drafts the send-to-HC email per RFI for Rocky review. Tracks response state (sent / responded / closed / superseded) so RFI hygiene becomes systematic across bids.
model: claude-sonnet-4-6
phase: 3 (after bid-prep step 3 AND continuously through Phase 4-5)
invoked_by: post-bid-prep auto-trigger OR Rocky-typed command
preconditions:
  - bid-prep doc complete with RFI candidates surfaced
  - drawing index complete with `NOT supplied` items flagged
  - intake envelope sealed
inputs:
  - job_no
  - source_files (list of worker outputs to scan: bid-prep doc, drawing index, Pre-Pricing-Grill, BoQ-from-drawings)
  - hc_contact (optional — for send-email drafting)
outputs:
  - `06 - Correspondence/06b - RFIs/RFI-Register-{job_no}.md` — append-only structured register
  - per-RFI draft email at `06 - Correspondence/06b - RFIs/RFI-{N}-draft-email.md`
  - state-tracking entry per RFI: status (open / sent / responded / closed / superseded)
  - assumptions-log addendum for any RFI-driven new auto-decisions
side_effects:
  - never auto-sends emails (Rocky reviews drafts before send per §3.2 confidentiality seam)
  - tracks RFI status in state.json under `state.json.bids.{job_no}.rfis[]`
authored_by: claude-code-orchestrator
created: 2026-05-10
---

# lfo-rfi-extract

RFI capture + prioritisation + draft + tracking. Currently free-form in worker output (e.g. session-80b1f893-2627 line 99-109 lists 9 RFIs with no formalisation). Each bid's RFI list is rebuilt from scratch.

## Why this exists

RFIs are a recurring artefact across every LFCS bid. Bid-prep step 3 surfaces RFI candidates inline; drawing-extract surfaces "NOT supplied" lists; sanity-check surfaces ambiguities. Without a skill:
- RFIs scattered across multiple worker outputs
- No consistent prioritisation
- No tracking (sent? responded? still open?)
- Redrafting send-emails from scratch per RFI

This skill consolidates + structures.

## Procedure

### 1. Read source candidates

Scan source files for RFI signals:

| Source | Signal pattern |
|---|---|
| Bid-prep doc | "RFI", "TBC", "to be confirmed", "clarify with HC", section flagged "Open Questions" |
| Drawing index | "NOT supplied", "missing", "deferred", "incomplete" |
| Pre-Pricing-Grill | Q-G* answers with TBC or "needs RFI" status |
| BoQ-from-drawings | "ADDED" rows without source drawing reference, ambiguous quantities |
| 03a Issued for Construction notes | Drawings noting "Refer to xxx" where xxx isn't supplied |

Parse each match into an RFI candidate dict:
- `description` (1-2 sentences)
- `source_file + line/section`
- `impact_category` (HIGH / MEDIUM / LOW — see step 2)
- `quantity_confidence_impact` (e.g. "±20-30%")
- `dollar_estimate_if_quantifiable`

### 2. Prioritise

Apply impact rules:

- **HIGH:** quantity confidence impact ≥±20% OR dollar estimate ≥$10k OR scope-defining ambiguity (e.g. is X in or out of LFCS scope?)
- **MEDIUM:** quantity confidence impact 10-20% OR dollar estimate $2-10k OR programme-affecting clarification
- **LOW:** quantity confidence impact <10% OR dollar estimate <$2k OR cosmetic/non-pricing

Worked example from session-80b1f893-2627 RFI list:
1. Architectural setout — HIGH (quantity ±20-30%)
2. Programme dates + continuous-run — MEDIUM
3. Piering S100/S200 "may be required" — MEDIUM
4. Shelter shop drawings — LOW-MEDIUM
5. Working hours + Saturday allowance — LOW
6. Stormwater drainage — LOW
7. Concrete grade 32 vs 35 MPa — LOW $
8. Pavement spec §1 St Ives template — NIL $
9. Flexural beam testing retention — LOW

### 3. Write structured register

`06 - Correspondence/06b - RFIs/RFI-Register-{job_no}.md` (append-only):

```markdown
---
job_no: {job_no}
purpose: RFI register for bid {job_no}. Append-only. Status updated in-place via cross-reference (look up by RFI ID).
created: {iso-now}
authored_by: claude-code-orchestrator (lfo-rfi-extract)
append_only: true
---

# RFI Register — Job {job_no}

| RFI ID | Created | Description | Source | Impact | $-estimate | Status | Sent date | Response received | Closed date |
|---|---|---|---|---|---|---|---|---|---|
| RFI-{job_no}-001 | {iso} | Architectural setout for slab tier 2 | bid-prep §6 line 23 | HIGH | quantity ±25% (~$15k) | open | — | — | — |
| RFI-{job_no}-002 | {iso} | Programme dates + continuous-run pour confirmation | bid-prep §8 line 41 | MEDIUM | productivity uplift if not continuous | open | — | — | — |
...

## RFI batch surfaced 2026-05-10 (Phase 3 step 3)

(per-RFI rationale: 1 sentence each on what triggered the RFI)

## Status update log (append-only)

(each status change appends one line: RFI-ID | new-status | timestamp | actor)
```

### 4. Draft send-to-HC emails

Per RFI, write `06 - Correspondence/06b - RFIs/RFI-{job_no}-{NNN}-draft-email.md`:

```markdown
---
rfi_id: RFI-{job_no}-{NNN}
draft_status: pending-Rocky-review
created: {iso}
to: {hc_contact_or_TBC}
from: {operator_of_record_or_TBC}
---

Subject: RFI {NNN} — Bid {job_no} — {short description}

Hi {first_name},

We're working on the {job_name} bid and need clarification on the following before we can finalise pricing:

{description in 2-3 sentences}

**What we need:**
{specific question or document request}

**Impact on our pricing:**
{1 sentence on what changes once answered}

**Timing:** {ASAP / by {date} / before tender close}

Thanks,
{operator}
LFCS Pty Ltd
```

DO NOT auto-send. Rocky reviews each draft before send per §3.2 confidentiality seam.

### 5. Update state tracking

Append to `state.json.bids.{job_no}.rfis[]`:
```json
{
  "rfi_id": "RFI-{job_no}-001",
  "status": "open",
  "created_at": "{iso}",
  "impact": "HIGH",
  "draft_email_path": "{path}"
}
```

### 6. Surface to Rocky

Use `AskUserQuestion` ONCE per batch:
> "{N} RFIs extracted from {sources}. {H} HIGH / {M} MEDIUM / {L} LOW. Open the register to review, send the HIGH ones first, or batch-send all?"

Rocky reviews + decides per-RFI: send / amend / hold / supersede.

### 7. Track response

When Rocky says "RFI {NNN} got response: {text}":

- Append response to register row
- Update status: `responded`
- Append to status log
- Surface to Rocky: "Update assumptions log + downstream pricing for RFI-{NNN} response?"
- If yes, append addendum to `_Internal/assumptions-log-{job_no}.md` "## RFI-driven updates" section
- If response materially changes a §13 auto-decision: queue lessons-learned candidate

### 8. Close on bid-submitted

When Phase 6 closes (bid submitted), summarise:
- N RFIs raised total
- N still open at submission (flagged in covering letter as caveats)
- N closed
- N response-pending
- Append closing section to register

## Failure modes

- **Worker output has zero RFI candidates** when scope is complex: STOP, surface — possibly worker missed them; ask Rocky if drawings are missing from extraction.
- **Same RFI raised in two source files**: dedupe by description-similarity (≥80% match); cross-reference both sources in register.
- **HC contact unknown**: leave `to:` field as TBC; surface to Rocky to populate before send.
- **Rocky overrides priority** (HIGH → LOW): respect override + log reason in register.

## Notes

- RFI hygiene matters: late-stage RFIs that should have been raised at Phase 1-3 hurt credibility with HC. Run this skill EARLY (post-bid-prep) and ITERATE through Phase 4.
- RFI register is permanent record. Never delete, even if RFI superseded — mark status, don't remove.
- Future enhancement: correlate RFI patterns across HCs to surface "questions HC X always answers slowly" → factor into intake-envelope `programme_buffer` decisions.
