---
name: lfo-submission-gate
description: Invoke when Phase 4 sanity-check is complete AND Rocky has typed "send" / "submit" / "go" / "approved for submission" — the explicit external-submission authorisation gate per CLAUDE.md §6 trigger 6. Captures the authorisation timestamp + Rocky verbatim quote into the session log + audit-trail. Drafts the submission-build worker prompts per Q-F4 (LoO + BoQ-response per intake). Monitors Layer 1 + Layer 2 sanitisation results from the worker per `lfcs-pricing` §4.3 — ON L2 FAIL halts immediately + surfaces per §6 trigger 7 (artefact deleted by worker, no retry without root-cause).
model: claude-sonnet-4-6
phase: 6
invoked_by: Rocky-typed authorisation OR autonomous-daemon detecting `phase-4-sanity-complete` + Rocky-input gate response
preconditions:
  - Phase 4 closed (overrides captured + comparison logged + proposals queued)
  - Rocky's literal authorisation captured ("send" / "submit" / equivalent — not paraphrased)
  - Q-F4 format decision locked from intake envelope (lump-sum-letter | boq-response | both)
inputs:
  - job_no
  - rocky_authorisation_text (verbatim quote — for audit-trail)
  - rocky_authorisation_timestamp (iso)
  - format (from Q-F4: `lump-sum-letter` | `boq-response` | `both`)
  - operator_of_record (Liam Fitzgerald | Hus | Rocky — drives the LoO signature block)
  - recipient_email (HC contact for send)
outputs:
  - drafted submission-build prompts (one per format if Q-F4 = both)
  - L1 + L2 sanitisation result captured in session log per artefact
  - Bid record `Status=Submitted` + `Submitted_Date` + `final_submitted_total_ex_gst` + `final_authored_by` + `Rocky_Authorisation_Timestamp` + `Rocky_Authorisation_Quote`
  - audit-trail entry with full sanitisation pass/fail trace
side_effects:
  - on Rocky authorisation captured: opens external-submission lane (irreversible once worker sends)
  - on L2 fail: artefact deleted by worker; orchestrator halts; NO retry per CLAUDE.md §6 trigger 7
authored_by: claude-code-orchestrator
created: 2026-05-10
---

# lfo-submission-gate

Phase 6 owner. Currently inlined in `lfo-bid-lifecycle` SKILL.md:122-128. This skill encapsulates the gate logic: capture authorisation, draft sanitisation+build prompts, monitor L2, halt-on-fail.

## Why this exists

Phase 6 is the most consequential gate in the system — once Rocky says "send", external send happens within minutes. Three things must be perfect:
1. **Authorisation evidence** — Rocky's verbatim quote + timestamp captured for audit-trail (legal compliance — never post-hoc reconstruct what Rocky said)
2. **Format dispatch** — Q-F4 from intake drives which build skill the worker invokes (lfcs-loo-builder vs lfcs-boq-response-builder vs both)
3. **L2 fail-closed contract** — per CLAUDE.md §6 trigger 7, L2 sanitisation failure deletes the artefact + halts the entire flow with NO retry until root-cause investigation

Without a dedicated skill, this lives in lfo-bid-lifecycle prose. Edge cases (L2 fail mid-batch when format=both, Rocky rescinds mid-build, recipient changes after authorisation) are unhandled.

## Procedure

### 1. Capture authorisation evidence

When Rocky's input matches authorisation language (`send` / `submit` / `go` / `approved for submission` / `ship it` — case-insensitive; Rocky-typed exactly, not paraphrased by the orchestrator):

Write to session log under `## Phase 6 — Submission authorisation`:

```yaml
authorisation_captured:
  rocky_text_verbatim: "<exact Rocky message>"
  timestamp: <iso-now>
  channel: <terminal | handoff-bus | other>
  prior_state: <session phase before authorisation>
```

Also append to `_Internal/audit-trail/submission-authorisation-{job_no}-{date}.md` (append-only):

```markdown
## Submission Authorisation — Job {job_no}

- Rocky verbatim: "{text}"
- Captured at: {iso-now}
- Operator of record (signs LoO): {Liam | Hus | Rocky}
- Format dispatch: {lump-sum-letter | boq-response | both}
- Recipient: {email}
- Bid sealed total ex GST: ${X:,.0f}
```

### 2. Verify Phase 4 closed

Read session log for Phase 4 outcome:
- `## Phase 4 — sanity-check + overrides` block exists with: override_count, net_delta_dollars, transcript_summary
- envelope-comparison file exists (or Phase 3.5 confidence <60 documented)

If Phase 4 not closed, STOP. Surface to Rocky: "Phase 4 not closed. Cannot send. Run sanity-check first."

### 3. Look up format dispatch

Read intake envelope from session log for `Q-F4` answer:
- `lump-sum-letter` → invoke worker skill `lfcs-loo-builder`
- `boq-response` → invoke worker skill `lfcs-boq-response-builder`
- `both` (defensive default per proposed §13 rule) → invoke both, sequentially

### 4. Draft submission-build prompts

For each format dispatch, draft a worker prompt block. Template:

```markdown
{INTAKE-ENVELOPE — re-used from sealed Phase 1}

ROCKY-AUTHORISED FOR EXTERNAL SEND — captured at {timestamp} in session {session_id}.
Verbatim: "{rocky_text}"
Operator of record: {Liam | Hus | Rocky}
Company: LF Construction Services Pty Ltd

Run submission build per CLAUDE.md §4.3:
- Format: {lump-sum-letter | boq-response}
- Skill: {lfcs-loo-builder | lfcs-boq-response-builder}
- operator_of_record: {name}
- final_submitted_total_ex_gst: ${X:,.0f}
- recipient_email: {email}

Run Layer 1 sanitise, then Layer 2 verify (independent).

Fail-closed contract: if L2 fails:
1. Delete artefact
2. Log _Internal_Sanitisation_Log.verified_by_human=NEVER
3. Do NOT retry
4. Surface failure to orchestrator

On L2 pass + human-verification gate ({operator} opens Drive preview, confirms Author=human + no agent terms in body, sets verified_by_human=true):
- Drive upload via `lfcs-drive-upload.sh`
- Auto-share with mcloughlinmichael.r@gmail.com Editor no-notify
- Email send to {recipient}

After send:
- Update Bids.Status=Submitted
- Submitted_Date=<iso-now>
- final_submitted_total_ex_gst=${X:,.0f}
- final_authored_by=<operator>
- Rocky_Authorisation_Timestamp={timestamp from step 1}
- Rocky_Authorisation_Quote="{rocky_text}"
```

Relay via `lfo-handoff-watcher` write-mode.

### 5. Monitor sanitisation results

Watch `pricer-to-orch.md` for the worker's sanitisation report. Parse:
- `layer_1_pass: yes | no | partial`
- `layer_2_pass: yes | no | failed_safe`
- `human_verification: yes | no | pending`
- `artefact_path: <Drive URL>` (only on L2 pass + human verify)

### 6. Halt-on-fail

If `layer_2_pass != yes`:

- IMMEDIATELY surface to Rocky per §6 trigger 7
- Log L2 failure in audit-trail with full reason
- Do NOT auto-retry. Do NOT auto-edit and re-submit. Do NOT batch any other format dispatch (if Q-F4=both, halt the second build too)
- Set Bid `Status=L2-FAIL-HOLD` + `L2_Fail_Reason` + `L2_Fail_Timestamp`
- Surface message: "L2 sanitisation failed for {format} on bid {job_no}. Reason: {detail}. Artefact deleted by worker. NO RETRY without root-cause investigation per CLAUDE.md §6 trigger 7. Do you want me to (a) investigate the root cause, (b) hold the bid, or (c) escalate to manual sanitisation?"

### 7. On full success

If all formats passed L2 + human verify + send:

- Update Bid record fields per step 4 prompt
- Append to session log `## Phase 6 — Submission complete`:
  ```yaml
  format: {value}
  drive_url: {value}
  email_sent_to: {recipient}
  email_message_id: {if captured}
  send_timestamp: {iso}
  ```
- Set `state.json.current_phase = phase-6-submitted`
- Daemon notification: "bid {job_no} submitted (priority default)"

### 8. Trigger Phase 7

Phase 6 success → invoke `lfo-lessons-write` for session close.

## Failure modes

- **Rocky's authorisation language ambiguous** (e.g. "looks ok" / "i think we're good"): STOP. Re-prompt with "Type 'send' to authorise external submission, or 'hold' to defer." Do NOT interpret ambiguous language as authorisation.
- **Rocky rescinds after authorisation** ("wait, hold on"): if before worker has invoked sanitisation, halt the worker via handoff bus + revert state.json. If after L2 pass + send, surface to Rocky — already sent; would need recall procedure (separate).
- **Recipient email missing or invalid:** STOP, surface to Rocky for correction before proceeding.
- **Worker session unresponsive >5 min:** surface, ask Rocky for retry decision.
- **L1 partial pass:** treat as fail. L2 only runs if L1 fully passes per `lfcs-pricing` §4.3 contract.
- **Both formats fail L2 at the same time:** halt twice; report both failures; do NOT auto-conclude one is salvageable.

## Notes

- Rocky's verbatim authorisation quote is legal evidence. Never paraphrase. Never compress. Never post-hoc reconstruct.
- The skill never bypasses the L2 fail-closed contract. Even if Rocky tries to override in-session ("just send it anyway") the orchestrator must STOP per §3.5 forbidden actions.
- Future enhancement: support multi-recipient sends (HC + estimator + project manager). Out of scope for v1.
