# Ticket #000045 — Prometheus-Σ Phase 3 sleep-sweep scheduler

**Status:** open · doc-only scaffold · awaits §3 retrigger gate satisfaction
**Opened:** 2026-05-10
**Parent:** #000037 (Prometheus-Σ recursive falsification controller)
**Scope:** Pin the governance parameters and the measured retrigger
signal under which Phase 3 — the actual sleep-sweep scheduler that
runs the Phase 1 controller on a cadence over real shards, not as a
one-shot dry-run — opens. **No implementation in this ticket.** The
ticket is the gate; the implementation lands in a follow-up commit
chain only after the retrigger fires.
**Audience:** fox + future blackops shifts + downstream Phase 3
implementer + auditors of governance_policy_hash inputs.
**Hard constraint:** doc-only Phase 0. **No** schema bump, **no**
governance_policy_hash bump in this ticket. The list of governance
parameters in §2 is a *commitment* — when Phase 3 lands, those exact
fields fold into `governance_policy_hash` so the controller's
operating policy is hash-pinned alongside chunker / canonicalization
/ schema versions. Until retrigger: dry-run continues to drive the
Phase 1 controller via `make prometheus-sweep-dryrun`, and the
advisory writes from Phase 2 (`controller_events` table populated
by `_emit_qa_controller_advisory` on every QA cycle) accumulate as
the live signal that will eventually justify opening Phase 3.

---

## 1. Problem statement

Phases 1 + 1.b + 1.c + 2 of #000037 landed the controller, the
sibling audit table, the QA-runner advisory wiring, the `kernel_cost`/
`llm_cost` cost-class split, and the `sweep_weights()` profile. The
read-only dry-run simulator (`bench/scripts/prometheus_sigma_sweep_dryrun.py`)
exercises the controller against real shard data. What is **not**
landed: the loop that runs the controller continuously, schedules
witness fan-out across the Hermes concurrency budget, and writes
back falsification proposals into the 5F battery in production.

Phase 3 is that loop. It is the difference between *measuring*
controller decisions in a dry-run report and *acting* on them
during ingestion lulls. It is also the point where the controller
stops being advisory and starts spending real Hermes budget on
re-witness work — which is why the gate is measured, not
calendar-driven (mirrors #000037 §12 discipline).

The five dry-run findings (#000037 §22) are the design substrate
that informs Phase 3. Two of them landed directly in #000037 Phase
1.c + dry-run iteration 2026-05-10:

- **Finding 2 RESOLVED** — `kernel_cost` / `llm_cost` split shipped
  in commit `4b85a0a`; `sweep_weights()` profile shipped in same.
- **Finding 3 RESOLVED** — per-audit-mode τ_qa shipped in dry-run
  via `build_tau_by_mode()` and `--tau-qa-cp-days` / `--tau-qa-days`
  CLI flags in commit `1f882df`.

The remaining three findings (Finding 1 chunk-size, Finding 4
Target B headline, Finding 5 quarantined-row veto) become Phase 3
implementation constraints, not controller-substrate edits.

---

## 2. Governance parameters (commitment)

When Phase 3 lands, these fields fold into
`governance_policy_hash` so the running scheduler's operating
policy is hash-pinned. Bumping any one stales every prior advisory
row written by `_emit_qa_controller_advisory` AND every prior
sweep result. Listed here as commitment so the Phase 3
implementation cannot quietly add fields without re-reading this
ticket.

| field | type | default | meaning |
|---|---|---|---|
| `phase3_chunk_size` | int | `4` | branches per controller invocation; tracks Hermes concurrency (#000037 §11). Per Finding 1 this MUST equal the witness-fan-out budget, never the candidate-pool size. |
| `phase3_tau_qa_cp_seconds` | int | `86400` (1d) | per-mode τ_qa for `CANONICAL_PROJECTION` rows — kernel-only re-probe is cheap (Finding 3). |
| `phase3_tau_qa_llm_seconds` | int | `604800` (7d) | per-mode τ_qa for STRICT / HYBRID / UNGROUNDED rows — full LLM re-witness is expensive (Finding 3). |
| `phase3_weight_profile` | str | `"sweep"` | `WEIGHT_PROFILES[…]` key driving controller utility weights. Default is `sweep` (γ_5f=1.5, λ_capital_cost=0.25, ν_witness_divergence=0.5) per Phase 1.c. |
| `phase3_active_targets` | tuple[str, …] | `("A",)` | which sweep targets run per cycle. `"A"` = providence_cache re-witness; `"B"` = document canonical-shape probe (Finding 4 — adds ~152K candidate funnel). Phase 3 opens with A only; B requires its own retrigger. |
| `phase3_per_window_budget` | int | `64` | hard cap on Hermes calls per sweep window (Finding 4 — sustained-throughput floor + per-window cap, not one-shot burst). |
| `phase3_window_cadence_seconds` | int | `3600` (1h) | scheduling cadence between sweep windows; chosen so the 5F-fixture funnel (Finding 4) fills in batches the falsification harvester can drain. |
| `phase3_quarantined_policy` | str | `"hard_veto"` | how `falsification_state='quarantined'` rows are handled — Finding 5 confirmed `cache_drift` hard-veto exercises end-to-end; this field locks that behavior in policy. |

**Not** in `governance_policy_hash`: anything that is purely
operational (logging level, output paths, debug toggles). The hash
covers what the controller would *decide differently* under a
different value.

---

## 3. Retrigger gate (when does Phase 3 open?)

Phase 3 opens **only** when one of these signals fires. Mirrors
#000037 §12 discipline: measured pressure, not calendar date. Each
trigger names what we are measuring and where to look for it.

**Retrigger 1 — advisory-row pattern stability.** After ≥ 1,000
advisory rows have accumulated in `controller_events` from the
Phase 2 QA-runner wiring (i.e., ≥ 1,000 live QA cycles), AND the
controller's decision distribution shows reproducible structure
(not noise — concretely: REJECT/DEFERRED ratio std-dev across
rolling 100-row windows < 0.10 and ≥ 1 ACCEPT/MARGINAL row per
100-row window). Signals that the cheap advisory layer is already
producing actionable structure that a sweep loop could amplify.

```sql
-- Sketch of the retrigger query (run against any qa.db shard):
SELECT COUNT(*) AS n_rows
FROM controller_events
WHERE event_kind = 'controller_decision';
-- If n_rows < 1000 → Retrigger 1 has not fired.
```

**Retrigger 2 — sustained Target A acceptance.** Three consecutive
weekly dry-run reports (`make prometheus-sweep-dryrun` with
default per-mode τ) show ≥ 1 ACCEPT chunk on Target A AND ≥ 5
MARGINAL chunks. Signals that the per-mode τ split is producing
sustained sleep-work signal, not a one-week artifact.

**Retrigger 3 — Target B 5F-fixture funnel demand.** The 5F
battery (#000025) shows that the harvested fixture pack
(`bench/fixtures/5f/falsification-harvested-v1.jsonl`) is
plateauing or shrinking — i.e., Target A's 5F-proposal stream is
no longer adding novel falsification candidates and the harvester
needs Target B's larger candidate funnel (Finding 4 —
extrapolated ~152K canonical-probe candidates) to keep growing the
fixture corpus. Concrete signal: < 5 net new fixtures over 2
consecutive weekly harvest runs.

**Retrigger 4 — operator mission need.** fox-stated need
(e.g., shipping a particular textbook ingest with nightly
re-validation, or an oncall response to a measured drift event).
Bypasses the measured gates because it is an explicit go. Mirrors
#000037 §12 Trigger 4.

Until at least one of these fires: the dry-run continues to drive
the controller via `make prometheus-sweep-dryrun`, the QA runner
continues to write advisory rows, and the 5F battery continues
to harvest fixtures from the static Phase 1 proposal stream.

---

## 4. Out of scope

- **No scheduler implementation.** No daemon, no systemd unit,
  no cron, no asyncio loop. This ticket commits to the parameter
  surface and the gate; the loop lands in the Phase 3
  implementation ticket that this ticket gates.
- **No schema migration.** The `controller_events` sibling table
  from #000037 Phase 2 already exists; Phase 3 reuses it for
  sweep results. No new tables in this ticket.
- **No `governance_policy_hash` bump in this ticket.** The hash
  bump happens when Phase 3 lands (so the parameter values become
  part of the policy commitment). Until then `governance_policy_hash`
  is unaffected by this scaffold.
- ~~**No `sweep_weights()` swap in the dry-run.**~~ Resolved
  same-day under #000037: commit `6734f80` (2026-05-10 19:22 EDT,
  ~3 minutes before this ticket was opened) swapped both call
  sites in `prometheus_sigma_sweep_dryrun.py` from
  `safe_weights()` to `sweep_weights()` and labeled the report
  "Weight profile: sweep" via #000037 §15.4. The dry-run report
  numbers were intentionally allowed to drift from prior-bench
  comparability since the sweep profile is the operationally
  correct one for sleep-sweep economics (γ_5f=1.5,
  λ_capital_cost=0.25, ν_witness_divergence=0.5) — not the safe
  profile. Future bench-comparability work, if needed, would re-
  bench against `safe_weights()` as a calibration baseline, not
  flip the dry-run back.
- **No Hermes call planner.** Phase 3 will need to plan witness
  fan-out across `phase3_chunk_size` × `phase3_per_window_budget`
  budget — that planner is a sub-design inside the Phase 3
  implementation, not a separate ticket.

---

## 5. References

- #000037 — parent ticket; §12 phase triggers (mirrored here),
  §22 dry-run findings (substrate for §2 parameters).
- `bench/scripts/prometheus_sigma_sweep_dryrun.py` — read-only
  simulator that drives the Phase 1 controller against real
  shards. Becomes Phase 3's calibration substrate.
- `bench/results/prometheus-sigma-sweep-dryrun-2026-05-10.md` —
  current dry-run report with per-mode τ_qa applied.
- #000025 — 5F battery; Retrigger 3 reads its harvested-fixture
  growth rate as a Target B demand signal.
- #000028 — multi-witness canonical agreement; supplies the
  divergence-rate signal that Retrigger 1 watches accumulate.
- #000020 — capital ledger; surfaces the witness-budget pressure
  that Retrigger 4 might cite as operator mission need.
- `arborist/substrate/prometheus.py` — `WEIGHT_PROFILES` registry
  (`safe` / `conservative` / `exploratory` / `sweep`) that
  `phase3_weight_profile` selects from.
- `arborist/qa/runner.py` `_emit_qa_controller_advisory` — Phase 2
  wiring whose accumulated rows Retrigger 1 measures.
