---
name: lfo-bid-lifecycle
description: Single-command bid lifecycle. Rocky types "start bid {job-id} from {inbound-path}" in lfo terminal; this skill drives Phases 1→7 end-to-end via the handoff bus + daemon, surfacing only the 7 hard cases per §6. Phase 3.5 reverse-engineer-budget runs in parallel with Phase 3-4 worker pricing where feasible. Final notification "bid {id} ready for review" fires on Phase 6 close.
model: claude-sonnet-4-6
phase: orchestration root (calls every other lfo-* skill)
invoked_by: Rocky's "start bid X from Y" prompt in the lfo terminal
preconditions:
  - handoff folder exists at `C:/Users/mclou/lfcs-handoff/`
  - state.json valid; `active_bid_id` is null OR matches the requested bid (resume case)
  - daemon recommended but not required (without it, Rocky shepherds via "check handoff" prompts)
  - lfp terminal open (or scheduled to open) — degraded one-session mode supported per orchestrator §9 footnote
inputs:
  - job_id (string, e.g. "2631")
  - inbound_path (string, e.g. "C:/Users/mclou/lfcs-inbound-artefacts/2631/...")
  - skip_envelope (optional bool, default false) — disables Phase 3.5 reverse-engineer-budget
  - skip_blind (optional bool, default true) — Phase 5 only fires if Rocky names a comparator at start
outputs:
  - assumptions log populated at `_Internal/assumptions-log-{job-id}.md`
  - priced take-off + exclusions list + drawing index in the job folder
  - envelope comparison at `_Internal/budget-envelope-comparison-{job-id}.md` (if Phase 3.5 ran)
  - sanity-check overrides log
  - sanitised submission artefacts at the per-job 02a folder (only if Rocky-authorised at Phase 6 entry)
  - phone notification "bid {id} ready" on Phase 6 close
  - lessons-write fires on Phase 7
side_effects:
  - writes to handoff folder + job folder + Airtable (via worker)
  - daemon notifications fire on each handoff-file modification + Rocky-gate stalls
authored_by: claude-code-orchestrator
created: 2026-05-08
---

# lfo-bid-lifecycle

The orchestrator's top-level driver. One command, end-to-end run, only-7-hard-cases stop policy.

## Activation

Rocky types in lfo terminal:
```
start bid 2631 from C:/Users/mclou/lfcs-inbound-artefacts/2631/Issued for Construction-...
```

Or shorthand if inbound is in canonical location:
```
start bid 2631
```

(Skill auto-discovers RFQ pack at `C:/Users/mclou/lfcs-inbound-artefacts/{job_id}/...` if no path given.)

## Procedure

### Pre-flight (5 seconds)

1. **Read `state.json`.** If `active_bid_id` is set and matches `job_id`: resume in-place from `current_phase`. If set and differs: refuse — append new bid to `queue.md` and surface to Rocky "active bid {X} in progress; queued bid {Y} for after Phase 7." If null: proceed.
2. **Read prior orchestrator session** for this `job_id` if exists (`_Internal/orchestrator-sessions/session-*-{job_id}.md`). Resume from `last_phase_completed` if found.
3. **Validate inbound path.** If `inbound_path` not provided AND `C:/Users/mclou/lfcs-inbound-artefacts/{job_id}/` doesn't exist: stop, surface, ask Rocky for the inbound path.
4. **Spawn orchestrator session log** at `_Internal/orchestrator-sessions/session-{uuid}-{job_id}.md` with frontmatter (session_id, job_no, started_at, agent=lfcs-orchestrator, paired_worker=lfcs-pricing, mode=lifecycle).
5. **Set state.json** `active_bid_id={job_id}`, `bid_started_at=<iso now>`, `bid_inbound_path=<path>`, `current_phase=phase-1-intake`.

### Phase 1 — Autonomous intake (5–15 min)

Per orchestrator CLAUDE.md §5.1:
1. Apply `lfo-intake-gate` skill (priority-chain runner). Walks §5.0 chain on the 6 standing questions + any RFQ-derived bid-specific questions.
2. Each row written to `_Internal/assumptions-log-{job-id}.md` with source citation + confidence.
3. Run gap-watch checkpoints; flag G2-shadow or G6-shadow if drawing-spec contradicts an auto-decision.
4. Build the intake-locked envelope.
5. **Surface the assumptions log to Rocky** (one batched gate via `AskUserQuestion`):
   > "Auto-decided N. Flagged M (confidence ≥60% but material). Open K. Push through, override individual rows, or hold for review?"
6. If Rocky pushes through OR all rows are auto-decided ≥60% with no flags: advance to Phase 2 silently. If any row is flagged + Rocky hasn't responded: enter Rocky-input gate (set `rocky_gate_active=true`); daemon escalation kicks in.

### Phase 2 — Standard exclusions (3–8 min)

Per orchestrator CLAUDE.md §5.2:
1. Apply `lfo-standard-exclusions-apply` skill. Reads `standards/Standard-LFCS-Exclusions-Library.md`.
2. Auto-decide where rule = `always-out` or `always-in`. Flag `always-RFI` rows for Rocky's confirmation.
3. Seed the per-job exclusions skeleton at `_Internal/exclusions/exclusions-{job-id}.md` in 2629 three-tier shape.
4. Append to assumptions log under section "Exclusions (auto-applied + flagged)."
5. Surface flagged-for-Rocky rows in the same batched gate as Phase 1 (or separately if Phase 1 already cleared).

### Phase 3 — Worker pricing via handoff (15–60 min depending on take-off complexity)

Per orchestrator CLAUDE.md §5.3. **Delegates to `lfo-prompt-pricing` (single source of truth for prompt content). Do NOT duplicate templates here.**

For each step in the worker workflow sequence, invoke `lfo-prompt-pricing` with:
- `step={step-name}` (one of: `drawing-extract`, `boq-parse`, `bid-prep`, `phase-0-grill`, `first-pass`, `sanity-check-open`, `submission-build`)
- `prior_worker_output=<last 50 lines from pricer-to-orch.md>` (if applicable)

`lfo-prompt-pricing` produces the body. Pipeline:

1. `lfo-prompt-pricing(step=drawing-extract)` → body
2. Body wrapped + written to `orch-to-pricer.md` via `lfo-handoff-watcher` (write mode). Daemon notifies pricer terminal.
3. Wait for `pricer-to-orch.md` updates. Read each via `lfo-handoff-watcher` (read mode) on Rocky's "check handoff" or daemon notification.
4. Run `lfo-gap-watch` rules G1–G5+ against each pricer output before invoking the next step.
5. Repeat for `boq-parse` → `bid-prep` → `phase-0-grill` → `first-pass` → `exclusions-list draft (three-tier 2629-style)`.
6. **Worker bottom-up total SEALED** when first-pass priced take-off lands. Set `current_phase=phase-3-sealed`.

**Refactor note (2026-05-10):** previously this section inlined the 6 worker prompt templates verbatim from `lfo-prompt-pricing` SKILL.md:25-152. Removed in favour of delegation pattern — single source of truth for prompt content. If a step is added (e.g. RFI extraction), update `lfo-prompt-pricing` only.

After Phase 3 sealed, **invoke `lfo-rfi-extract`** to capture RFI candidates from worker output (bid-prep + drawing index + Pre-Pricing-Grill). Surface to Rocky for review/send before sanity-check.

### Phase 3.5 — Reverse-engineer budget (parallel with Phase 4 sanity-check)

Per orchestrator CLAUDE.md §5.3.5:
1. Verify orchestrator's working context does NOT have the bottom-up total. If it does, abort 3.5 (envelope would be biased).
2. Apply `lfo-reverse-engineer-budget` skill with `skip_quarantine=false` for live bids.
3. Web research (max 5 calls per envelope build) → allocation% → HC margin → exclusion deductions → envelope band.
4. Output to `_Internal/quarantined/budget-envelope-{job-id}.md`. Path added to pricer's path-exclusion patterns.
5. **In parallel**, Phase 4 sanity-check can begin (the worker doesn't need the envelope output to do override capture).

### Phase 4 — Sanity check + envelope reveal (5–20 min)

Per orchestrator CLAUDE.md §5.4. **Delegates to `lfo-sanity-check-driver` (Phase 4 owner).**

Invoke `lfo-sanity-check-driver` with:
- `job_no`
- `bottom_up_total_ex_gst` (from Phase 3 sealed)
- `participants` (Rocky + Liam | Rocky + Hus | Rocky-only)
- `capture_mode` (typed | voice | mixed)

Skill handles: envelope unquarantine + delta comparison + outcome classification (inside ±15% / below >15% / above >15%) + worker override-capture session prompt + methodology proposal queueing.

After skill returns: set `current_phase=phase-4-sanity-complete`.

### Phase 5 — Blind comparison (only if applicable)

Per orchestrator CLAUDE.md §5.5:
- **Only fires** if `skip_blind=false` AND Rocky named a comparator at start (`start bid 2631 from {path} blind-compare against={comparator}`).
- Apply `lfo-blind-driver` skill.
- **REVEAL gate is one of the 7 hard cases.** Wait for Rocky-typed `REVEAL`. No auto-trigger.

### Phase 6 — External submission (Rocky-gated)

Per orchestrator CLAUDE.md §5.6. **Delegates to `lfo-submission-gate` (Phase 6 owner).**

Invoke `lfo-submission-gate` with:
- `job_no`
- `rocky_authorisation_text` (verbatim)
- `rocky_authorisation_timestamp` (iso)
- `format` (from Q-F4)
- `operator_of_record` (Liam | Hus | Rocky)
- `recipient_email`

Skill handles: authorisation evidence capture + Q-F4 dispatch + L1/L2 sanitisation monitoring + halt-on-fail per §6 trigger 7 + Bid record updates + daemon notification on success.

After skill returns success: invoke `lfo-lessons-write` for session close.

### Phase 7 — Lessons-write + close

Per orchestrator CLAUDE.md §5.7:
1. Apply `lfo-lessons-write` skill. Re-scan session log for new gap-patterns + missed-fires (Rocky-flagged).
2. Write to `_Internal/lessons-learned/{date}-{job-id}-{slug}.md` + sibling shared `C:/Users/mclou/lfcs-lessons-learned/lesson-{date}-{slug}.md` per cross-link discipline.
3. Update `standards/gaps-pattern-library.md` if a new pattern is sufficiently general (Rocky-confirmed).
4. Append one-liner to `_Brain/_Log.md`.
5. Close orchestrator session log (ended_at, lessons_written, proposals_queued count).
6. **Reset state.json** `active_bid_id=null`, `current_phase=null`, `rocky_gate_active=false`. Process any entries in `queue.md` (next bid).
7. **Notify Rocky:** "bid {id} ready for review" (priority `default`).

## Hard-case stop policy (unchanged)

Stop and ask Rocky ONLY on the 7 hard cases per §6. All other gates auto-resolve via the priority chain + assumptions-log review pattern. Worker silence >2 min per old §7 is downgraded — orchestrator surfaces the worker output, may retry, may fall back to one-session degraded mode, only escalates if pattern matches one of the 7.

## Failure modes

- **State.json corrupted:** stop, surface, ask Rocky whether to recover from `state.json.tmp` if present, or rebuild.
- **Inbound path unreadable:** stop, surface (hard rule risk: file-system access).
- **Daemon offline AND Rocky not in either terminal:** lifecycle stalls at first handoff write. State.json captures position; resume on next Rocky engagement. NOT a stop trigger by itself.
- **L2 sanitisation failure (Phase 6):** hard case 7. Halt, surface immediately. Artefact deleted by worker.
- **Web research budget exceeded (Phase 3.5):** envelope returns confidence <60% → log "envelope confidence too low for sanity-check comparison" → Phase 4 proceeds without envelope (NOT a stop).

## Worked example — what happens when Rocky types "start bid 2631"

```
Rocky (lfo terminal): start bid 2631 from C:/Users/mclou/lfcs-inbound-artefacts/2631/

Orchestrator (~5 sec): 
  - reads state.json (no active bid), validates inbound path (exists)
  - spawns session log
  - sets state.json active_bid=2631, phase=phase-1-intake

Orchestrator (~3 min):
  - runs lfo-intake-gate priority chain on Q-1..Q-6 + bid-specific questions
  - 5 of 6 auto-decided ≥85% confidence
  - 1 flagged-for-Rocky (e.g. site exposure ambiguity at 65%)
  - assumptions log written
  - daemon notifies Rocky's phone: "Auto-decided 5/6 intake. 1 flagged.
    Open lfo terminal to review."

Rocky (lfo terminal, when convenient): 
  - reads assumptions log
  - confirms or overrides flagged row
  - says "go"

Orchestrator (~30 sec):
  - clears rocky_gate_active
  - runs Phase 2 standard exclusions auto-decide
  - drafts Phase 3 prompt sequence
  - writes first prompt to orch-to-pricer.md (drawing extract)
  - daemon notifies pricer terminal: "Pricer: new prompt — bid 2631"

Pricer (lfp terminal):
  - reads orch-to-pricer.md
  - runs lfcs-drawing-extract-text + vision per prompt
  - writes output to pricer-to-orch.md
  - daemon notifies orch terminal: "Orch: pricer output ready"

Orchestrator (continues):
  - reads pricer output, runs gap-watch, drafts next prompt (BoQ parse)
  - Phase 3 cycles through all 6 worker steps
  - bottom-up sealed at end of Phase 3
  - Phase 3.5 envelope build runs in parallel with Phase 4 sanity-check
  - all auto-decisions logged

Orchestrator (~Phase 6):
  - waits for Rocky-typed "send" (hard case 6)
  - daemon escalates if Rocky stalls 30/60/90 min

Rocky (eventually, may be hours later): "send"

Orchestrator (~3 min):
  - drafts L1+L2 sanitisation prompts
  - pricer runs sanitisation, generates external artefact
  - drive upload + email send
  - Airtable Bids Status=Submitted
  - Phase 7 lessons-write fires
  - state.json reset
  - daemon notification: "bid 2631 submitted, ready for review"
```

Total Rocky touchpoints: 2-3 (Phase 1 review gate; Phase 6 send authorisation; potentially Phase 5 REVEAL if blind-compare). Roughly 5-10 minutes of Rocky's time spread across the bid duration vs the prior 1-2 hours of question-answering.

## Notes

- This skill is a procedure spec, not a service. The orchestrator agent EXECUTES the procedure across multiple turns/sessions. The handoff folder + daemon provide the cross-session glue.
- v1 supports the basic flow. Future v2 enhancements: parallel Phase 3.5 + Phase 4 already designed but synchronisation logic untested at scale; refine after first 3 live bids.
- "Rocky walks away" is the design goal. Reality v1: Rocky checks his phone for notifications, returns to the terminal when needed (Phase 1 review, Phase 6 send), still significantly less burden than the prior question-by-question pattern.
