---
name: lfo-bcs-rotate-and-sweep
description: Invoke when (a) a Blind-Comparison Session aborted on breach (BCS Airtable row status=ABORTED-BREACH) and Rocky wants to retry, OR (b) Rocky-typed "rotate handoff" / "sweep BCS leak" / "Path-D recovery". Rotates the handoff bus files, archives predecessor blocks to audit-trail, sweeps all worker-readable files (per-job CLAUDE.md, 00-brief.md, exclusions skeleton, orch-to-pricer.md) for BCS metadata leaks (comparator filename / author / total / supersession marker / scope-split delta / schema label), and writes the next worker prompt as whitelist-only (no blacklist enumeration). Pattern derived from 2026-05-08 sessions d58cec3f + 09c7347d that aborted on this exact failure.
model: claude-sonnet-4-6
phase: pre-Phase-3 retry after BCS breach
invoked_by: orchestrator on detection of `ABORTED-BREACH` status, OR Rocky-typed command
preconditions:
  - prior session marked ABORTED-BREACH per CLAUDE.md §3.4
  - Rocky-confirmed clean retry window (per `lfcs-pricing` §4.5 abort-on-breach contract)
  - active_bid_id matches the bid being recovered
inputs:
  - bid_id (string)
  - predecessor_session_ids (list of breached session UUIDs)
  - breach_taxonomy (one of: `orchestrator-authored-leak`, `handoff-bus-superseded-block`, `worker-readable-quarantine-notice`, `comparator-filename-in-refuse-list`)
outputs:
  - rotated handoff files (`orch-to-pricer.md` + `pricer-to-orch.md` reset to clean state, archives stamped)
  - swept worker-readable files (BCS metadata stripped from per-job CLAUDE.md / 00-brief.md / exclusions skeleton / state.json)
  - new whitelist-only worker prompt drafted at `orch-to-pricer.md` msg-index=1
  - audit-trail entry at `_Internal/audit-trail/bcs-recovery-{bid_id}-{date}.md`
side_effects:
  - mutates handoff folder + state.json
  - archives predecessor-bus blocks to read-only audit-trail
  - sets new orchestrator session_id; prior session marked ABORTED-BREACH-CLOSED
authored_by: claude-code-orchestrator
created: 2026-05-10
---

# lfo-bcs-rotate-and-sweep

Codify the Path-D recovery pattern that played out manually across 2026-05-08 sessions d58cec3f + 09c7347d on bid 2627. Both sessions aborted on BCS leaks the orchestrator authored into worker-readable files. Recovery required: file rotation + sweep + whitelist-only re-write. Encode it so it's fast + correct + repeatable.

## Why this exists

BCS-leak breaches will recur on every blind-comparison bid until tooled. The 2026-05-08 episode demonstrated:
- d58cec3f leaked via `00-brief.md` `## Comparator` section (6 strip-required items, orchestrator-authored)
- 09c7347d leaked via raw `Read` of `orch-to-pricer.md` returning superseded msg-index=1 (author + temporal tag + schema label)

Both leaks happened DESPITE existing protocols. The fix per `lesson-2026-05-08-handoff-bus-bcs-leak.md` (queued as candidate, written as part of this skill's lessons-learned set):
- **Whitelist > blacklist.** Blacklists leak the very thing they protect (e.g. "do not read X" mentions X).
- **File rotation > block-edit.** Once leaked, an in-place edit is insufficient — the prior block remains readable on raw `Read`. Rotate means archive + truncate + restart.
- **Author identity (no $-figure) breaks BCS independence via anchoring bias.** Even "Liam Fitzgerald" without his quote total contaminates.

This skill is the architectural fix. Without it, BCS retries depend on operator memory of which files to sweep + how to rotate cleanly.

## Procedure

### 1. Pre-flight verification

Read `C:/Users/mclou/lfcs-handoff/state.json`:
- Confirm `active_bid_id` matches input `bid_id`
- Confirm prior session(s) status: read each `_Internal/orchestrator-sessions/session-{uuid}.md` for `status: ABORTED-BREACH`
- Confirm Rocky has explicitly authorised retry (look for "retry BCS" / "Path-D" / "rotate" in recent input)

If any check fails, surface to Rocky per §6 trigger 1 (hard rule risk).

### 2. Archive predecessor handoff bus

Move current handoff state to read-only archive:

```
C:/Users/mclou/lfcs-handoff/orch-to-pricer.md   →   _Internal/audit-trail/handoff-archive-{bid_id}-pre-{iso-timestamp}.md  (append "## ARCHIVED orch-to-pricer.md" header)
C:/Users/mclou/lfcs-handoff/pricer-to-orch.md   →   same file, append "## ARCHIVED pricer-to-orch.md" header
```

Archive file is append-only. Atomic write (temp + rename).

### 3. Reset live handoff bus to clean state

Truncate `orch-to-pricer.md` and `pricer-to-orch.md` to empty. Atomic write.

### 4. Strip BCS metadata from `state.json`

Remove fields that leak comparator identity:
- `comparator_artefact` (path)
- `comparator_name` (display string)
- `comparator_author_name`
- Any `comparator_*` field except an opaque `comparator_handle` like `"Comparator-A"` (single letter ID, no descriptive value)

Keep:
- `active_bid_id`, `current_phase`, `bid_started_at`, `rocky_gate_active`, `comparator_handle` (opaque)

### 5. Sweep worker-readable files

For each worker-readable file in the active job:

| File | Sweep target |
|---|---|
| `Operations/Jobs/Upcoming/{job_no} - {name}/CLAUDE.md` | Remove ALL "comparator" / "BCS" / refuse-list / quarantine-notice strings. Keep only LFCS standard content + per-job pointers. |
| `Operations/Jobs/Upcoming/{job_no} - {name}/00-brief.md` | Remove `## Comparator` section + any "do not read X" lines + author names other than HC contacts |
| `_Internal/exclusions/exclusions-{job_no}.md` | Remove "assumed" softening; replace with definitive language so worker can't infer prior-comparison context |
| `state.json.comparator_*` | Already done in step 4 |
| Any per-job markdown referencing comparator paths | Sweep verbatim string matches |

Pattern detection (use these regex on every file):
- `comparator|Comparator|COMPARATOR`
- `Liam.{0,30}quote|Hus.{0,30}quote` (author + word "quote")
- Filenames matching `*Comparator*`, `*_v-CW*`, `*-blind-compare-*`
- `_internal_quarantined_for_session_id` references
- `pre.IFC.posture.split` or `scope.split.delta` schema labels

If any match found in a file you're going to keep: **edit the file to remove the match**, NOT just flag it. Verify post-edit with a re-grep.

### 6. Rewrite worker-readable instruction context

For per-job CLAUDE.md and 00-brief.md, the new content is **whitelist-only**:

```markdown
## Read these paths only

- {path-to-RFQ-or-IFC-drawings}
- {path-to-BoQ}
- {path-to-spec}

Do not enumerate sibling folders. Do not search for prior pricing. Do not read any file in `_Internal/`.
```

NO refuse-list. NO "do not read X" with X named. Pure whitelist.

### 7. Spawn fresh orchestrator session

Generate new `session_id` (UUID). Write `_Internal/orchestrator-sessions/session-{new-uuid}-{bid_id}.md` with frontmatter:

```yaml
---
session_id: {new-uuid}
job_no: {bid_id}
job_name: {name}
started_at: {iso-now}
agent: lfcs-orchestrator
paired_worker: lfcs-pricing
mode: lifecycle
operating_mode: {from state.json}
bcs_active: true
comparator_handle: Comparator-A  # opaque, no name
predecessor_sessions: [{uuids of breached predecessors}]
recovery_path: D
authored_by: claude-code-orchestrator
append_only: true
---

# Orchestrator session — {bid_id} (Path-D rotation restart)

## Restart pre-flight

Predecessor sessions aborted on BCS breaches:
{per-predecessor: session_id + breach_taxonomy + resolution}

## Files swept
{list of files swept in step 5}

## Phase 1 intake — re-used (no Rocky touchpoint repeated)

Phase 1 priority-chain decisions stand. Locked envelope unchanged: {summary}.
```

### 8. Write Phase 3 first prompt to rotated bus

Append `orch-to-pricer.md` msg-index=1 with:

```markdown
<!-- orch-msg-start bid={bid_id} ts={iso-now} phase=phase-3-worker msg-index=1 -->
## Bid {bid_id} — Phase phase-3-worker — {iso-now}

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

Read these two paths only:
- {path-1}
- {path-2}

Do not enumerate sibling folders. Do not read any file in `_Internal/`. Do not search for prior pricing.

{6-step task sequence per lfo-prompt-pricing standard}

Append a single pricer-msg block to `pricer-to-orch.md` when complete.
<!-- orch-msg-end -->
```

NO comparator name, path, filename pattern, "comparator" word, or BCS-quarantine notice in worker-readable text. The opaque whitelist is sufficient defence.

### 9. Audit-trail entry

Write `_Internal/audit-trail/bcs-recovery-{bid_id}-{date}.md`:

```markdown
---
recovery_session: {new-uuid}
bid_id: {id}
predecessor_sessions: [{uuids}]
recovery_path: D
breach_taxonomies: [{list}]
files_swept: [{list}]
fields_stripped: [{list}]
authored_by: claude-code-orchestrator (lfo-bcs-rotate-and-sweep)
created: {iso-now}
---

# BCS Path-D Recovery — Bid {bid_id}

## What broke
{per-predecessor: 1-2 sentences citing the leaked artefact + pattern matched}

## What was rotated
{per-file: pre-rotation hash → archive path → post-rotation hash}

## What is locked going forward
- whitelist-only worker prompts
- opaque comparator_handle in state.json
- no refuse-list strings in worker-readable files
- file rotation (not block-edit) on any future leak

## Lessons-learned candidate
Append `lesson-{date}-bcs-rotation-recovery-{bid_id}.md` to `C:/Users/mclou/lfcs-lessons-learned/` if pattern repeats (n=2+).
```

### 10. Daemon notification

If daemon running: it picks up the rotated bus mtime change and notifies pricer side. Otherwise Rocky shepherds.

## Failure modes

- **Sweep finds match in a file we shouldn't auto-edit (e.g. Rocky's notes in `_Internal/`):** flag, don't edit; surface to Rocky to manually decide.
- **state.json corrupted during strip:** restore from `state.json.tmp` if present; else surface to Rocky.
- **Predecessor handoff archive is huge (>10MB):** still archive; do not truncate. Audit-trail integrity matters more than disk.
- **Post-sweep grep STILL finds matches:** STOP. Re-run sweep with broader patterns. Surface to Rocky with the un-sweepable matches before retry.
- **Rocky has not authorised retry:** STOP per §6 trigger 1. Do NOT auto-rotate.

## Notes

- This skill encodes one specific recovery path (Path-D from session-80b1f893). Other paths may emerge; codify each as a separate sub-skill or branch.
- Companion: gap-watch rule G6 (BCS-metadata in worker-readable) — if G6 fires pre-leak, this skill never needs to run.
- After 3 successful invocations without re-breach, consider tightening the upstream G6 rule to make this skill obsolete by prevention.
