Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions backend/core/ouroboros/governance/candidate_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,22 @@
return False


def _dw_autarky_enabled() -> bool:
"""Slice 225 Phase 2 master. Default-TRUE — when the Claude fallback breaker
is OPEN/HALF_OPEN (terminal_quota / out-of-credits / transport), STANDARD and
COMPLEX ops keep the DW primary on the full op budget instead of severing it
at the 30s/75s reflex cap into a dead lane (the live GOAL-001::file-00
generation_failed wedge). Sibling to the P2.1 IMMEDIATE-route gate above, for
the STANDARD/COMPLEX primary-budget path. Operator force-off with =0. NEVER
raises — fail-closed to legacy cascade."""
try:
return os.environ.get(
"JARVIS_DW_AUTARKY_ENABLED", "true",
).strip().lower() in ("1", "true", "yes", "on")
except Exception: # noqa: BLE001
return False


def immediate_reroute_to_dw(
*,
dw_is_primary: bool,
Expand Down Expand Up @@ -4945,9 +4961,36 @@
_force_batch = _slice36_should_force_batch(context)
except Exception: # noqa: BLE001 — defensive, legacy budget
_force_batch = False
# Slice 225 Phase 2 — Sovereign DW Autarky. Read the Claude fallback
# breaker (read-only, no probe side effect — same _claude_breaker_open
# predicate the Slice 127 P2.1 IMMEDIATE reroute uses). When the
# fallback lane is OPEN/HALF_OPEN (incl. terminal_quota / out-of-
# credits), there's no live lane to sever DW into — give DW the full
# runway instead of the 30s/75s reflex cap. Gated default-TRUE;
# OFF (or breaker CLOSED) is the byte-identical legacy cascade.
_fallback_dead = False
if _dw_autarky_enabled():
try:
from backend.core.ouroboros.governance.doubleword_provider import (
_claude_breaker_open as _autarky_breaker_open,
)
_fallback_dead = _autarky_breaker_open()
except Exception: # noqa: BLE001 — fail-closed to legacy cascade
_fallback_dead = False
primary_budget = self._compute_primary_budget(
remaining, model_id=model_id, force_batch=_force_batch,
fallback_dead=_fallback_dead,
)
if _fallback_dead and primary_budget > _PRIMARY_MAX_TIMEOUT_S:
logger.warning(
"[CandidateGenerator] ⚡ DW AUTARKY ENGAGED: Claude fallback "
"breaker OPEN — granting DW the full %.1fs budget (vs %.1fs "
"reflex cap), no dead-lane handoff. route=%s op=%s model=%s",
primary_budget, _PRIMARY_MAX_TIMEOUT_S,
getattr(context, "provider_route", "?"),
getattr(context, "op_id", "?")[:16],
model_id or "(unspecified)",

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This expression logs
sensitive data (secret)
as clear text.
This expression logs
sensitive data (secret)
as clear text.
)
# Slice 34 Phase 2 — dispatch profiler (default OFF; zero
# overhead when disabled). Records the sem-wait + budget
# stages into the per-op summary; STAGE_PROVIDER_GENERATE
Expand Down Expand Up @@ -6486,6 +6529,7 @@
*,
model_id: str = "",
force_batch: bool = False,
fallback_dead: bool = False,
) -> float:
"""Deterministic Tier 1 primary budget with fallback reserve + Tier 3 cap.

Expand Down Expand Up @@ -6541,6 +6585,24 @@
batch_cap = _envf_or_default("JARVIS_DW_BATCH_TIMEOUT_S", 300.0)
return max(min(total_s, batch_cap), 0.0)

# Slice 225 Phase 2 — Sovereign DW Autarky. When the Claude fallback
# lane is unreliable (breaker OPEN/HALF_OPEN — incl. the terminal_quota
# / out-of-credits economic refusal), there is NO live fallback to hand
# off to. Severing DW at the 30s/75s reflex cap only accelerates
# exhaustion into a dead lane — the live-soak GOAL-001::file-00 wedge:
# DW cut at 30s -> Claude 400 "credit balance too low" -> EXHAUSTION,
# generation_failed, no patch ever produced. Give DW the full remaining
# runway up to a cost-safety ceiling instead (default 180s = the COMPLEX
# generation window). Mirrors the force_batch precedent directly above
# ("Claude disabled -> no fallback to reserve -> full runway"). The
# caller stamps fallback_dead from the read-only _claude_breaker_open
# predicate; default False is byte-identical to the legacy cascade.
if fallback_dead:
autarky_cap = _envf_or_default(
"JARVIS_DW_AUTARKY_MAX_BUDGET_S", 180.0,
)
return max(min(total_s, autarky_cap), 0.0)

fb_reserve = min(_FALLBACK_MIN_RESERVE_S, total_s * 0.35)

# Slice 28 Phase 2 — adaptive Tier 3 cap for heavy models
Expand Down
76 changes: 70 additions & 6 deletions backend/core/ouroboros/governance/doubleword_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -2324,6 +2324,35 @@ def _s194_on_abandoned(
except Exception: # noqa: BLE001
pass

# Slice 227 — context-aware hedge governor. When the Iron Gate
# will demand exploration for this op (the SAME predicate that
# re-opens the tool loop in Slice 226), the batch arm (no tool
# loop) must not pre-empt the exploring RT arm — its un-explored
# candidate would fail the exploration floor (the live
# GOAL-001::file-00 layer-3 bug). One source of truth across the
# capability, security, and concurrency planes. Rupture fallback
# is fully preserved (batch is buffered, used iff RT ruptures).
from backend.core.ouroboros.governance.dw_transport_hedge import (
hedge_gate_aware_enabled as _s227_governor_on,
)
_s227_prefer_fast = False
if _s227_governor_on():
try:
from backend.core.ouroboros.governance.exploration_engine import ( # noqa: E501
exploration_gate_demands_tools as _s227_gate_demands,
)
_s227_prefer_fast = _s227_gate_demands(
str(getattr(context, "task_complexity", "")),
)
except Exception: # noqa: BLE001 — fail-open to legacy race
_s227_prefer_fast = False
if _s227_prefer_fast:
logger.warning(
"[Cortex] ⚡ HEDGE GOVERNOR: op needs Iron-Gate "
"exploration — batch arm held speculative, RT arm (tool "
"loop) gets the slot unless it ruptures (op=%s)",
(getattr(context, "op_id", "?") or "?")[:16],
)
return await hedged_race(
lambda: self._generate_realtime(
context, deadline, prompt_override=prompt_override,
Expand All @@ -2336,6 +2365,7 @@ def _s194_on_abandoned(
stable_label="batch",
on_outcome=_s190_hedge_outcome,
on_abandoned=_s194_on_abandoned,
prefer_fast=_s227_prefer_fast,
)
try:
# Slice 9.1 — thread repair_context for L2 single-shot
Expand Down Expand Up @@ -2754,12 +2784,46 @@ async def _generate_realtime(
# (the simple-background half of the v40b deadlock would otherwise
# remain: loop runs, tools suppressed). Env-gated + BACKGROUND-only
# -> byte-identical legacy when Claude is enabled / flag off.
if background_is_terminal_worker(str(_route)):
_will_skip_tools = (_complexity == "trivial")
else:
_will_skip_tools = (
_complexity in ("trivial", "simple")
or should_skip_venom_for_route(str(_route))
# Slice 226 — Iron Gate / provider capability alignment. The base
# tool-skip decision (BG-terminal-worker vs complexity/route skip) is
# now computed by the shared exploration_engine predicate so the
# capability plane (tools available) can never contradict the security
# plane (exploration floor). When the Iron Gate will demand exploration
# for a ``simple`` op on a venom-eligible route, the loop stays ON —
# closing the live GOAL-001::file-00 catch-22 (simple -> tools skipped
# -> exploration_insufficient -> guaranteed rejection). trivial stays
# exempt; BACKGROUND/SPECULATIVE keep their preload-credit skip.
from backend.core.ouroboros.governance.exploration_engine import (
compute_tool_loop_suppressed as _s226_compute_skip,
exploration_gate_demands_tools as _s226_gate_demands,
)
_s226_is_bg_tw = background_is_terminal_worker(str(_route))
_s226_route_skip = should_skip_venom_for_route(str(_route))
_base_skip = _s226_compute_skip(
complexity=str(_complexity),
route=str(_route),
is_bg_terminal_worker=_s226_is_bg_tw,
has_repair_context=False,
)
_will_skip_tools = _base_skip
# Slice 226 observability (operator pref: escalate capability anomalies
# LOUD, never silent re-route). When the alignment override re-opened
# the loop for a complexity that the cost heuristic would have stripped
# (simple, venom-eligible route, not BG-terminal-worker), flash it.
if (
not _base_skip
and not _s226_is_bg_tw
and not _s226_route_skip
and str(_complexity).strip().lower() == "simple"
and _s226_gate_demands(str(_complexity))
):
logger.warning(
"[DoublewordProvider] ⚡ CAPABILITY ALIGNMENT: Iron Gate floor "
"demands exploration for a 'simple' op — re-opened the Venom "
"tool loop (read_file/search_code) the cost heuristic would "
"have withheld. route=%s op=%s",
_route,
(getattr(context, "op_id", "?") or "?")[:16],
)
# ──────────────────────────────────────────────────────────────
# Slice 9 — L2 single-shot fast path (DW mirror)
Expand Down
85 changes: 71 additions & 14 deletions backend/core/ouroboros/governance/dw_transport_hedge.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ def transport_hedge_enabled() -> bool:
)


def hedge_gate_aware_enabled() -> bool:
"""Slice 227 master — the context-aware hedge governor. Default **TRUE**:
when an op faces the Iron Gate exploration floor, the batch arm is held
speculative so the tool-using RT arm gets the slot (rupture fallback intact).
OFF restores the byte-identical legacy FIRST_COMPLETED race. NEVER raises."""
return os.environ.get(
"JARVIS_HEDGE_GATE_AWARE_ENABLED", "true",
).strip().lower() in ("1", "true", "yes", "on")


def _storm_threshold() -> float:
try:
raw = os.environ.get("JARVIS_DW_STORM_SKIP_THRESHOLD", "").strip()
Expand Down Expand Up @@ -57,6 +67,7 @@ async def hedged_race(
on_abandoned: Optional[
Callable[[Optional[BaseException], Optional[BaseException]], None]
] = None,
prefer_fast: bool = False,
) -> Any:
"""Race ``fast`` (RT) against ``stable`` (batch). Return the FIRST successful result; cancel
the loser aggressively. A ``fast`` failure that ``is_rupture`` returns True for is swallowed so
Expand All @@ -72,7 +83,16 @@ async def hedged_race(
both arms resolved, neither succeeded — passing each arm's captured exception (None for an
arm that was cancelled / never errored). The caller's triage engine classifies the pair to
confirm a hard model/endpoint blockage and rotate candidates. Best-effort: a sink error never
changes the raise behavior; the abandoned race still raises its last exception."""
changes the raise behavior; the abandoned race still raises its last exception.

Slice 227 — ``prefer_fast`` (the context-aware hedge governor). When True, a winning STABLE
(batch) result does NOT pre-empt the race: it is held in a speculative buffer and the race
keeps waiting for the FAST (RT) arm. This is the gate-aware mode — the RT arm runs the Venom
tool loop (exploration), the batch arm does not, so an un-explored batch candidate that
arrives first would fail the Iron Gate's exploration floor (the live GOAL-001::file-00 layer-3
bug). The buffered batch is used ONLY if the RT arm then ruptures / fails / yields no success,
so the hedge's rupture-protection guarantee is fully preserved. ``prefer_fast=False`` (default)
is byte-identical to the legacy FIRST_COMPLETED race."""
loop = asyncio.get_event_loop()
t_fast = loop.create_task(fast())
t_stable = loop.create_task(stable())
Expand All @@ -81,6 +101,8 @@ async def hedged_race(
fast_exc: Optional[BaseException] = None
stable_exc: Optional[BaseException] = None
fast_ruptured = False
_UNSET = object()
buffered_stable: Any = _UNSET # Slice 227 speculative buffer (prefer_fast)

def _report(winner_label: str) -> None:
if on_outcome is not None:
Expand All @@ -89,10 +111,27 @@ def _report(winner_label: str) -> None:
except Exception: # noqa: BLE001 — telemetry never breaks the race
pass

async def _claim(result: Any, winner_label: str) -> Any:
# Cancel any still-pending loser + await its unwind, then report + return.
for other in pending:
other.cancel()
if pending:
await asyncio.gather(*pending, return_exceptions=True)
_report(winner_label)
return result

try:
while pending:
done, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED)
for t in done:
# Slice 227 — in prefer_fast mode, process the FAST arm first within a
# batch where both completed, so a co-completed RT success is taken
# over a stable success. Legacy (prefer_fast=False) keeps the original
# arbitrary set iteration → byte-identical.
done_iter = (
sorted(done, key=lambda t: 0 if t is t_fast else 1)
if prefer_fast else done
)
for t in done_iter:
try:
result = t.result()
except asyncio.CancelledError:
Expand All @@ -102,23 +141,41 @@ def _report(winner_label: str) -> None:
# Slice 194 — capture per-arm so a dual failure can be triaged.
if t is t_fast:
fast_exc = exc
if is_rupture(exc):
fast_ruptured = True
# Slice 227 — the RT arm failed. If we're holding a
# speculative batch result (prefer_fast), claim it now —
# the rupture/failure fallback the hedge exists for.
if buffered_stable is not _UNSET:
return await _claim(buffered_stable, stable_label)
# otherwise wait for the stable arm (still pending)
continue
else:
stable_exc = exc
# a fast-path rupture is non-fatal — let the stable path keep racing
if t is t_fast and is_rupture(exc):
fast_ruptured = True
continue
# a non-rupture fast error or a stable error: if the other is still
# pending, keep waiting; else propagate below
# (legacy comment preserved); a stable error waits for the other arm.
continue
else:
# FIRST SUCCESS — cancel the loser aggressively + await its unwind
for other in pending:
other.cancel()
if pending:
await asyncio.gather(*pending, return_exceptions=True)
_report(fast_label if t is t_fast else stable_label)
return result
# SUCCESS.
if (
prefer_fast
and t is t_stable
and buffered_stable is _UNSET
and t_fast in pending
):
# Batch won the race, but this op needs the RT arm's
# exploration to clear the Iron Gate. Hold batch in the
# speculative buffer and keep waiting for RT — do NOT
# cancel it. RT success supersedes; RT rupture falls back.
buffered_stable = result
continue
# FIRST usable SUCCESS — cancel the loser + return.
return await _claim(result, fast_label if t is t_fast else stable_label)
# Slice 227 — race drained with no live success. A buffered batch result
# (RT never produced a success) is still a valid candidate — use it.
if buffered_stable is not _UNSET:
_report(stable_label)
return buffered_stable
# both finished without a success
if last_exc is not None:
# Slice 194 — the race was ABANDONED (no winner). Hand both arms'
Expand Down
Loading
Loading