# GENERATED — DO NOT EDIT. Read-live, shipped mirror of the MASTER config `.env`. # Edit `.env` (the master); regenerate with `npm run sync:env` (runs on build). # Read as the lowest-precedence default layer: user ~/.cortex/.env > real env > this. # Nexus Cortex — Complete Environment Configuration Reference # ╔══════════════════════════════════════════════════════════════════════════════════╗ # ║ LEVER LEDGER — this file is the persistent record of where every config lever ║ # ║ stands. Each lever carries a "# [LEDGER @] STATUS — evidence" ║ # ║ line (ON | DARK/RETIRED | DARK/PENDING | DARK by design). Update the line when a ║ # ║ cell moves the verdict and when each iteration ships. Cell ledgers live in ║ # ║ .cortex/bench/r-*.md. K=5 CONFIG (verified 2026-09-06 @4.93.0, r-resolver-k5): ║ # ║ ON set + CORTEX_ENDTURN_GATE=true + CORTEX_ENDTURN_REQUIREMENTS=true + ║ # ║ ENABLE_WEBTOOLS=false (bench pin) + VISION_HELPER_MODEL on + TOOL_TIMEOUT_MODE=auto; ║ # ║ MENTOR_AUTO / EFFORT_TAIL / EFFORT_PULSE dark. Pin nexus-cortex@4.93.0 (4.90.0.s ║ # ║ timeout-promote was inert). Both models. ║ # ╚══════════════════════════════════════════════════════════════════════════════════╝ # THIS FILE IS THE MASTER CONFIGURATION DOCUMENT. # ───────────────────────────────────────────────────────────────────────────────── # Every harness lever lives here, with its value and its [LEDGER] annotation — the one # readable place to see and change what the harness does. Edit HERE. On build, this file # is mirrored to the committed, shipped `.env.defaults` (the same content), which the # harness reads LIVE as its lowest-precedence default layer — so a package upgrade ships # these values to every user automatically (nothing to regenerate, no keys to re-enter). # # PRECEDENCE (highest → lowest): a user's ~/.cortex/.env (their keys + deliberate # overrides) → the real shell/injected env → these defaults → the hardcoded floor. # # 🔴 SECRETS STAY BLANK HERE. This file is tracked and its mirror ships — provider API # keys must NOT carry values (they live in the environment / Replit Secrets / the user's # ~/.cortex/.env). The build FAILS if any secret key has a value here. # # An ACTIVE line is the shipped default (including `LEVER=false` to ship it OFF); a # COMMENTED line falls through to the hardcoded floor. Keep the [LEDGER] lines current. # ============================================ # API KEYS # ============================================ # A model is only available if its provider's key is set. Leave the rest blank. # Claude (Anthropic) — Fable / Opus / Sonnet / Haiku ANTHROPIC_API_KEY= # OpenAI — GPT / o-series OPENAI_API_KEY= # Gemini (legacy key; GEMINI_API_KEY takes priority when both are set) GOOGLE_API_KEY= # Gemini (preferred key; falls back to GOOGLE_API_KEY) GEMINI_API_KEY= # xAI — Grok XAI_API_KEY= # DeepSeek (the default model's provider) DEEPSEEK_API_KEY= # Nvidia (no standalone NVIDIA cards registered yet — currently reached via Cloudflare) NVIDIA_API_KEY= # Inception Labs (Mercury diffusion models — mercury-2) INCEPTION_API_KEY= # Cloudflare Workers AI (@cf/* models). Requires CLOUDFLARE_ACCOUNT_ID. CLOUDFLARE_API_TOKEN= # Cloudflare account id (paired with the token above) CLOUDFLARE_ACCOUNT_ID= # Alibaba Qwen (DashScope) — qwen-* models DASHSCOPE_API_KEY= # MiniMax — minimax-* models MINIMAX_API_KEY= # Moonshot AI (Kimi) — moonshot-* / kimi-* models MOONSHOT_API_KEY= # Zhipu AI (GLM) — glm-* models ZHIPU_API_KEY= # ── Hugging Face Inference Providers ───────────────────────────────────────── # Run the harness (and/or helper) on a hosted open model with just a token. # 1. Set a token below — HF_TOKEN, HUGGINGFACE_API_KEY, and HUGGINGFACE_TOKEN # are all accepted (HF_TOKEN is the `hf` CLI / hosting-platform standard). # 2. Set HF_MODEL_ID to a SERVED repo id (e.g. # openai/gpt-oss-120b — optional :fastest/:cheapest/:provider suffix). # 3. Use that same id as DEFAULT_MODEL_ID / HELPER_MODEL_ID (see MODEL CONFIGURATION). # HF serverless hosts mostly larger popular models; for small models use a local one. HUGGINGFACE_API_KEY= HUGGINGFACE_TOKEN= HF_MODEL_ID= # Optional — match the chosen model's specs (affects compaction). Defaults: 32768 / 4096. HF_MODEL_CONTEXT_WINDOW= HF_MODEL_MAX_OUTPUT= # ── HuggingFace Gradio Space (self-hosted model, native hf-space transport) ─── # Serve a model from a HF Gradio Space (free GPU via ZeroGPU on PRO). Deploy the # template at scripts/hf-space-template/, then set HF_SPACE_ID and select it with # DEFAULT_MODEL_ID=hf-space (or HELPER_MODEL_ID=hf-space). Needs HF_TOKEN. HF_SPACE_ID= # Optional: custom registry id (default 'hf-space'), specs, reasoning, tool support. HF_SPACE_MODEL_ID= HF_SPACE_CONTEXT_WINDOW= HF_SPACE_MAX_OUTPUT= HF_SPACE_REASONING= # When the hf-space model is the chosen model, the server auto-resumes the Space # on startup and pauses it on shutdown so a paid dedicated GPU never bills while # idle. Set to 'false' to leave the Space lifecycle entirely to you. HF_SPACE_AUTO_LIFECYCLE= # Ready-made per-model Space cards (Qwen3 0.6B/1.7B, Qwen3.5 0.8B/4B, SmolLM3 3B, # Phi-4-mini, LFM2.5 350M). Set HF_SPACE_ID_ to a Space serving that model # (one Space per model, callable in parallel), e.g.: # HF_SPACE_ID_QWEN3_0_6B= HF_SPACE_ID_QWEN3_1_7B= HF_SPACE_ID_QWEN3_5_0_8B= # HF_SPACE_ID_QWEN3_5_4B= HF_SPACE_ID_SMOLLM3_3B= HF_SPACE_ID_PHI_4_MINI= # HF_SPACE_ID_LFM2_5_350M= # Or set HF_SPACE_CANDIDATES=true to point ALL of them at the shared HF_SPACE_ID # above (serial use; swap the Space's MODEL_ID variable between models). The # transport verifies the Space's [MODEL=...] prefix against each card and errors # on mismatch, so a card can never silently answer with the wrong model. HF_SPACE_CANDIDATES= # ── Local / self-hosted inference ──────────────────────────────────────────── # Run the harness (and/or helper) on your own OpenAI-compatible server — LM Studio, # llama-server, vLLM, Ollama. Select it via DEFAULT_MODEL_ID=local or HELPER_MODEL_ID=local. # Run the server with tool parsing ON (e.g. llama-server --jinja, vLLM # --enable-auto-tool-choice) so it returns native tool_calls the harness understands. # Blank endpoint = LM Studio default (http://localhost:1234/v1/chat/completions). LOCAL_MODEL_ENDPOINT= LOCAL_MODEL_API_KEY= # Optional — match your loaded model's specs (affects compaction). Defaults: 32768 / 4096. LOCAL_MODEL_CONTEXT_WINDOW= LOCAL_MODEL_MAX_OUTPUT= # Set true for a reasoning model that emits a separate reasoning_content field (run it # with thinking on). Off by default. Mirrors DeepSeek/CF reasoner handling. LOCAL_MODEL_REASONING= # Authentication method for Anthropic: auto (try OAuth first, fall back to API key), # oauth (OAuth only), api-key (API key only). Options: auto, oauth, api-key ANTHROPIC_AUTH_METHOD=api-key # OAuth token override (alternative to ~/.claude/.credentials.json) CLAUDE_CODE_OAUTH_TOKEN= # ============================================ # MODEL CONFIGURATION # ============================================ # Default model for new sessions (any registry ID or alias — `cortex models list`) # Optimal TB2 apprentice tier — pairs with the pro MENTORSHIP_HELPER_MODEL (stronger mentor). # [LEDGER 2026-09-02 @4.89.0] ON — flash is the apprentice (cheap, ties/edges frontier under the narrow door); pro = leaderboard candidate (TB2.1 n=1 78.7% guardless, ~82% projected guarded). DEFAULT_MODEL_ID=deepseek-flash # Cheaper model for context compaction & auxiliary helper calls (web-fetch summary, error guidance, # the ReadImage/describeImage vision hand-off). VISION-CAPABLE default (2026-09-09): flash-vision-exp # is SAME cost ($0.14/$0.28), near-identical text (bench-arm parity flash vs flash-vision), + adds # vision so ONE helper card also serves the image hand-off (VISION_HELPER_MODEL can collapse into it). # 🔴 LATENT: compaction + tool-result summarization currently FLATTEN image blocks to text before the # helper (handleToolResultOverflow JSON.stringify's content; renderBlock has no image case → drops it), # so vision only helps the explicit describeImage path TODAY. Realizing it for tool-results/compaction # needs a follow-up that emits image parts (HelperMiddlewareAdapter already supports `image` blocks). # Mentor roles override this via MENTORSHIP_HELPER_MODEL below (stay deepseek-v4-pro). # [LEDGER 2026-09-10 @4.102.0] deepseek-flash — DeepSeek catalog collapse: `deepseek-flash` IS V4.1 Flash (vision native, same # price as the retired v4-flash / vision-exp names, which now route here anyway). One helper card, no alias risk. HELPER_MODEL_ID=deepseek-flash # Model that backs WebSearch / WebFetch tools. Provider auto-detected from ID prefix. # When unset, auto-picks based on available API keys (Gemini > Anthropic > XAI), # falling back to DuckDuckGo HTML scrape if no provider key configured. # # Gemini models (uses @google/genai SDK — googleSearch grounding + urlContext): # gemini-2.5-flash — fast, free-tier friendly, good grounding with citations # gemini-2.5-flash-lite — cheapest, fewer grounding chunks but still functional # gemini-2.5-pro — best grounding quality (most chunks/supports), slower # gemini-3.5-flash — latest GA flash, strong agentic grounding, search + url context # gemini-3.1-pro-preview — latest pro preview, rich grounding, slowest # gemini-3-flash-preview — preview alias for gemini-3.5-flash # # Other providers (provider-native search APIs with citations): # claude-haiku-4-5 — Anthropic web_search server tool (inline source citations) # grok-4-fast-non-reasoning — XAI Responses API web_search (URL citations) # grok-4.3 — XAI Responses API web_search (reasoning model, URL citations) # PRODUCTION DEFAULT: unset (auto-pick by the user's available key, else DuckDuckGo). # A local Gemini override lives in the LOCAL-ONLY section at the bottom of this file. WEB_TOOLS_MODEL= # Web surface mode — auto | true | false (default auto). # auto — WebFetch stays ON (works keyless via the helper-summarizer ladder); WebSearch, Browse, # nexus-browser MCP tools and the provider-native hosted search (web_search / x_search) # turn ON only when a search-capable key is present (GOOGLE_API_KEY / GEMINI_API_KEY # for Gemini grounding, XAI_API_KEY, OPENAI_API_KEY). Keyless installs — the wall-page + # hallucination-pressure population (keyless A/B 2026-08-31) — get search off with no # configuration; keyed installs get everything with no configuration. # true — everything on. false — everything off: stripped from EVERY tool surface (factory # choke point, MCP assembly seam, hosted-search injection, SearchTools discovery, # {{toolNames}} prompt vars) AND refused at dispatch. # 🔴 Bench arms must PIN true/false explicitly: keyed bench containers carry job tokens for every # provider, so auto resolves ON there. Hot-toggleable. # [LEDGER 2026-09-03 @4.90.1] ON=auto (since 4.89.0) — v4 (bench pin false): 0 web refusals in either arm = the deny-list is clean and silent. — keyless A/B 08-31: wall pages + hallucination pressure; benches paid 3 taxes (pulse trigger fed by failing browse/WebFetch, Stage-5 unattested-web rejections, wasted turns). BENCH ARMS PIN false (keyed containers carry every provider token → auto=ON); c3 pinned false: 0 refusals, clean. Live: keyless 49 tools/WebFetch only; keyed 51/all; false 48/none. ENABLE_WEBTOOLS=auto # ============================================ # SYSTEM SETTINGS # ============================================ # Verbose debug logging (system-message assembly, routes). Toggle at runtime via /debug. DEBUG=false # Allow emoji in CLI output (false = plain text) USE_EMOJI=false # Project root the tools operate on. Leave EMPTY to use the launch cwd (the cwd # model, like Claude Code): cd into your project and run cortex. Only set this for # headless setups where the server's cwd is not the project. When set, it becomes # canonical and PROJECT_ROOT is derived from it (they can never diverge). PROJECT_PATH= # ============================================ # REACTIVE MENTORSHIP (AI-to-AI self-improvement) # ============================================ # Master switch for the mentorship system. ON = a stronger MENTORSHIP_HELPER_MODEL mentors # the primary model (AskForAdvice hints on thrash). Only meaningful when the primary # (DEFAULT_MODEL_ID) is WEAKER than the helper — a same-tier pair adds nothing. # [LEDGER 2026-09-02 @4.89.0] ON — the reactive helper layer (thinking-off helper). Baseline of every cell since 4.83; keep ON. MENTORSHIP_ENABLED=true # Forced-tool_choice backstop (AskForAdvice v2): on HIGH-confidence thrash, FORCE the model to # call AskForAdvice for one turn. Voluntary heed is ~0 (0/47 lifted transcripts), so forcing is # what actually makes the mentor fire. OFF by default — the v2 forcing path is not yet TB2-validated. # 🔴 MASTER GATE for the ENTIRE v2 forced-choice chain. Setting this =true (with MENTORSHIP_ENABLED=true) # is the ONLY thing that produces a forced tool_choice, which in turn activates ALL of the v2 provider # fixes for that forced turn: DeepSeek thinking-mode disable, tools-array restriction to the forced tool, # and parallel_tool_calls off. With this =false, every one of those paths is inert and request behavior # is byte-identical to pre-v2 (verified end-to-end 2026-08-29) — the code ships DARK. Flip to true only # after the forced-consult efficacy bench confirms it actually breaks the retry-loop. # [LEDGER 2026-09-02 @4.89.0] DARK/RETIRED — DeepSeek ignores forced tool_choice once ≥1 prior tool call exists (echo defect); superseded by CORTEX_MENTOR_AUTO. Keep false. CORTEX_MENTOR_FORCE=false # Thrash-detector tuning (feeds the forced-consult trigger above; inert while it is off). # Windowed density: CORTEX_THRASH_FAILS (default 4) failures within CORTEX_THRASH_WINDOW # (default 6) recent calls, after CORTEX_THRASH_MIN_TURNS (default 5) total calls. # CUMULATIVE (dilution-immune): real retry-loops interleave successful probes between # failing attempts (measured live: 15 fails/108 calls but max 2 per 6-window — the # windowed condition alone NEVER fires on them). CORTEX_THRASH_CUM_FAILS (default 12) # trips on total session failures instead. NOTE: pass/fail failure-count distributions # OVERLAP (the model grinds through 9-18 failures to genuine passes), so this is a # SOFT-steering trigger, not a stop signal — tune per deployment. #CORTEX_THRASH_FAILS=4 #CORTEX_THRASH_WINDOW=6 #CORTEX_THRASH_MIN_TURNS=5 # [LEDGER 2026-09-02 @4.89.0] code default 12 — cumulative session-failure trigger (windowed thrash fires at zero positions on real diluted loops); pass/fail fail-count distributions overlap → soft steering. Feeds MENTOR_AUTO + (retired) PULSE. #CORTEX_THRASH_CUM_FAILS=12 # AUTO-CONSULT (the DeepSeek-safe retry-loop breaker): on high-confidence thrash the # ORCHESTRATOR consults the mentor itself and injects the hint as a system-reminder on # the failing tool result — no dependence on the model calling AskForAdvice and no # forced tool_choice (which DeepSeek IGNORES whenever the history holds a prior # tool_call — provider echo defect, mapped 2026-08-30). Rate-limited by the same # per-session consult cap as the tool path. OFF by default — flip after the efficacy bench. # [LEDGER 2026-09-02 @4.89.0] DARK — NEUTRAL at n=2 (c3): engaged on every grind (2-4 injections), +1 dna-assembly / −1 chess (both n=1, flippy), retry_loop 7 = ctl 7, ~2× input tokens on grinds. m88 +1 engaged did not compound. Keep dark for k=5; pro→pro = harmful peer config regardless. CORTEX_MENTOR_AUTO=false # Ablation-ladder rung 1 (no-LLM mentor): when the auto/voluntary consult reaches a # real rung, inject a FIXED self-interrogation template instead of calling the helper # model — same trigger/ladder/rate-limit, zero cost. For pricing the mentor's # specificity margin (bench arms); not a production default. # [LEDGER 2026-09-02 @4.89.0] DARK/RETIRED — m88b: 0 flips / 0 regressions; safe but sterile (fewest loops, shifted to never_acted/wrong_artifact). Keep false. CORTEX_MENTOR_TEMPLATE=false # EFFORT PULSE ('think harder' ablation arm): on the same cumulative-thrash trigger, # escalate reasoning effort for the next N continuation requests (introspective # contrast to the mentor's fresh-context consult; independent of MENTOR_AUTO). # Cache-safe (verified: prefix cache survives mid-chain effort switches). # [LEDGER 2026-09-02 @4.89.0] DARK/RETIRED — m88r: fired 7× (dna-assembly ×6, pytorch-model-cli ×1), converted 0/2; distiller: burned budget on a time-constrained task. Depth mid-grind ≠ redirection. Keep false. CORTEX_EFFORT_PULSE=false # Pulse depth/level (continuations at elevated effort per trigger; level none|low|medium|high) #CORTEX_EFFORT_PULSE_TURNS=2 #CORTEX_EFFORT_PULSE_LEVEL=high # EFFORT TAIL (finish-discipline half): bounce the FIRST EndTurn of a turn once # ("verify at depth") and run the re-attestation cycle at the elevated effort — # structure forces the check (the gate), effort funds it. REQUIRES # CORTEX_ENDTURN_GATE=true (EndTurn must be offered); no-op otherwise. # [LEDGER 2026-09-02 @4.89.0] DARK — 0 at n=2 (c3): co-fired with the gate on 6/7 tasks; the fd protein-assembly flip did NOT replicate (0/2). Retire-candidate; keep false. CORTEX_EFFORT_TAIL=false #CORTEX_EFFORT_TAIL_TURNS=2 # ACTION EFFORT — static reasoning effort for the PRIMARY (action) model. Fills the request # param when unset, so it overrides the model CARD's default but NOT an explicit request param # or the dynamic effort-pulse. Mentor levers (LIFT_PLAN/ENDTURN_RESOLVER/DEADLINE_EXIT *_EFFORT) # are SEPARATE and stay at max. Values: low | medium | high | max (provider-dependent). Unset = # the card decides (deepseek cards = medium). Enables the pro-track "wide effort delta" A/B: # pro@low-action + pro@max-mentors (cheap decisive executor, deliberation quarantined to mentors). # [LEDGER 2026-09-06 @4.93.0] DARK/PENDING — lever built; UNTESTED (the 08-30 A/B was max-vs-medium, # never medium-vs-low). Floor risk: too low loses in-loop tool micro-reasoning. Arm in the fanout # cell (pro@low vs pro@medium vs pro@max action, mentors@max); winner → bake into the pro card's # reasoning.effortByRole.action (validate-then-bake). # [LEDGER 2026-09-07 @4.94.0] DARK/PENDING (n=1, dark-levers dlelo/dlemx + pro-effort pelo/pemd/pemx): # low = FLASH EFFICIENCY WIN (dlelo 33 turns/34.6K outTok/$1.635 vs dlctl 44/54.6K/$2.315, no pass # loss); max = REJECT (over-deliberates; pro@max pemx CUT mid-run — failed control at 67 turns/2x # tokens). PRO low≈medium too close (pe-lo/pe-md torn down at egress-rot). ⇒ flash-low confirmed at # n=1 → card reasoning.effortByRole.action bake pending k=5; pro-track k=5 (low vs med, mentors@max) # STILL OWED. Do NOT ship-on: n=1, k=5-gated. Stays dark/UNSET in production. # 🔴 LADDER FACT (DS API docs, 2026-09-09): reasoning_effort = {low, high, max} ONLY. 'medium' is # accepted but COERCED → 'high' server-side, so the card default 'medium' effectively runs HIGH. # ⇒ the flash-low verdict was low-vs-HIGH (not low-vs-medium): ~30% cheaper at pass-rate WASH. # Applies to the ACTION model here; the mentor roles run 'max' (top), the helper middleware runs 'none'. # [LEDGER 2026-09-11 @4.107.0] cell-n-r4 (hard core 13×K=2, flash action model, FINAL 47/52 rows): high = NO LIFT — ah-none 6/22 (0.27), ah-low 7/25 (0.28) vs control 11/26 (0.42); +3.5–4.5 min/task latency, turns unchanged (narrow door intact). Keep unset (card default). DARK. Ledger r-cell-n-r34. # [LEDGER 2026-09-12 @4.107.2] PRO @high on the k=5 series COMMON (tb21-k5-ph1, full 89, K=1): 72/89 = 80.9% (Wilson 0.72-0.88), $12.77, med 737 s — +3-4 pts over the flash series (77.3 ± 2.7), CIs overlap; effort NOT separated from model (pro @default not yet run). Flash @high = no lift (cell-n-r4). Stays DARK. Ledger .cortex/bench/r-tb21-k5-ph1-2026-09-12.md # [LEDGER 2026-09-18 @4.119.1] TB4.0 cell e6 (29 ever-passed tasks, 3-h budgets, flash, 1 repeat): LOW = REJECT 3/29 vs high 10/28 (+2/−9, p 0.07; tokens equal, wall +60%); MAX = WASH vs high 10/29 (+4/−4) at +30% tokens/+60% wall. Wire: reasoning/iteration FLAT across levels (4.6K/5.0K/4.8K chars), only the peak call scales (15.8K/22.7K/26.1K tok) — effort caps peak reasoning, not typical. Keep HIGH for TB4.0. Ledger r-tb4-e6-effort-2026-09-18.md. #CORTEX_ACTION_EFFORT= # Trigger helper-model review on tool errors (only applies when mentorship is enabled) MENTORSHIP_TRIGGER_ON_ERROR=false # Minimum error severity to trigger. Options: low, medium, high MENTORSHIP_ERROR_THRESHOLD=medium # React to @ultrathink / @analyze / @rethink keywords MENTORSHIP_KEYWORDS_ENABLED=false # Additional trigger keywords (comma-separated, e.g. @help,@stuck) MENTORSHIP_CUSTOM_KEYWORDS= # Model used for mentorship guidance (overrides HELPER_MODEL_ID). # MUST be a STRONGER model than the primary/apprentice model: the mentor gives HINTS the # weaker model cannot produce on its own (AskForAdvice), so a same-tier helper adds nothing. # Default = deepseek-v4-pro — still SINGLE-PROVIDER (reuses the main DeepSeek key, no 2nd API # key needed), just the stronger DeepSeek tier. Pair with DEFAULT_MODEL_ID=deepseek-v4-flash # (apprentice) so the mentor is genuinely stronger on the task. # (For image/vision background tasks, deepseek-v4-flash-vision-exp is the vision-capable option.) # [LEDGER 2026-09-02 @4.89.0] ON=pro — NEVER a same-strength mentor: flash→flash peer = −2 engaged (m88b, confident-wrong hints lost chess+tune-mjcf); pro elder = +1 engaged (m88). For a PRO apprentice this makes pro→pro = the harmful peer config → run pro with CORTEX_MENTOR_AUTO=false. # [LEDGER 2026-09-18] 🔴 V4 PRO IS NOT RETIRED — DeepSeek REINSTATED it (operator, repeated correction): "In response to user demand, we have decided to continue providing API services for DeepSeek V4 Pro after September 14, 2026, with the billing method remaining unchanged. We will provide further notice should there be any changes. Thank you for your understanding and support!" # deepseek-v4-pro serves V4 Pro weights, same billing; the 09-10 retirement note below is HISTORY, do not repeat it. # [LEDGER 2026-09-10 @4.102.0] deepseek-flash @max — V4 Pro is RETIRED 2026-09-14 04:00 UTC (routes to V4.1 Flash after # that). DeepSeek states V4.1 Flash surpasses V4 Pro; the mentor roles (lift/resolver/deadline/loop-exit, AskForAdvice) run # at effort max regardless of card. The "never a same-strength mentor" rule (m88b: v4-FLASH peer −2 engaged) was measured # against V4 flash; cell-m (2026-09-10) A/Bs pro@max vs deepseek-flash@max as the mentor on the loop population before # the k=5 pins it. Operator decision 2026-09-10. # [LEDGER 2026-09-10 @4.103.0] 🔴 "mentor @max" was NEVER on the wire before 4.103.0: the ChatCompletions helper adapter # sent thinking:{disabled} for every registry-resolved DeepSeek mentor call since 2026-08-30 (HB-MENTOR-THINKING). Every # lift plan / resolver verdict / deadline-exit / loop-exit / consult in every cell to date was a NON-thinking call. From # 4.103.0 the mentor's *_EFFORT (max) is sent as reasoning_effort. cell-m is the first cell with a thinking mentor. MENTORSHIP_HELPER_MODEL=deepseek-flash # [LEDGER 2026-09-10 @4.105.0] cell-m pilot thinking-OFF: pro-none 1/4 vs flash-none 2/4 (n=4, noise), both delivered ~5 KB plans + parsed verdicts in 5-9 s. STATUS: deepseek-flash (default) for the k=5 — V4 Pro routes to flash 2026-09-14 04:00 UTC anyway. # ── MENTOR ROLE (2026-09-10, training/mentorRole.ts) — the bounded single-shot judges/planners are a ROLE, distinct from # the HELPER role (HELPER_MODEL_ID: compaction/summaries/vision, thinking OFF). Model = MENTORSHIP_HELPER_MODEL above; # per-surface effort/budget/timeout = CORTEX_LIFT_PLAN_* / CORTEX_ENDTURN_RESOLVER_* / CORTEX_DEADLINE_EXIT_MENTOR_* / # CORTEX_LOOP_TOOL_BLOCK_* (below, in their sections); role-level switches here. Every mentor event banks # `mentor:{model,thinking,effort,budget}` = what the wire carried, so a ledger can prove the config. # CORTEX_MENTOR_REASONING — on|none. Whether the MENTOR surfaces (lift planner, EndTurn resolver, deadline exit, # loop-exit planner — the ones that pass an explicit *_EFFORT, default max) send that effort on the wire (thinking ON), # or keep the helper-role thinking-OFF behaviour (`none`). The AskForAdvice consult and all helper-role calls stay # thinking-off regardless (08-30: thinking-on hints came back blank — reasoning ate the small budget). # [LEDGER 2026-09-10 @4.104.0] on (default) — 🔴 every mentor result before 4.103.0 (resolver A/B 09-05, resolver k=5 09-06 # +17pp, cell-d-k3 judges) was measured with thinking OFF on the wire despite the "@max" configs (HB-MENTOR-THINKING); the # plans were real and non-empty even so. `none` reproduces that baseline. cell-m A/Bs {pro, deepseek-flash} × {on, none}. #CORTEX_MENTOR_REASONING=on # [LEDGER 2026-09-11 @4.107.0] cell-n-r1 (TB2.1 hard core 13 tasks x K=2, n~25/arm, $17.92 peak): CONTROL WINS — flash-none 10/24 (0.42) vs pro-high 9/25, flash-high 7/25, flash-max 7/26, fh-plan (planner on/resolver off) 7/25. Thinking-on resolvers false-accept ~50% vs 20% off; every thinking-on config costs 45-150 s per mentor call. STATUS: `none` CONFIRMED for the k=5; thinking-on DARK. Ledger .cortex/bench/r-cell-n-r1-2026-09-11.md # [LEDGER 2026-09-11 @4.106.1] cell-m-r1 (5 arms, n=8): DELIVERY FIXED for flash — flash-high 18/18 mentor calls delivered (11 thinking-on, 7 thinking-off-retry at the 16K cap); flash-max/pro-high hit the 90 s surface timeouts (→ 4.106.2). Rates: thinking-on arms 5/8 ×3 vs none 4/8, 3/8 — direction only, CIs overlap. STATUS: `none` stays the k=5 COMMON; proper A/B = flash-none vs flash-high on 4.106.2 + ALLOWANCE=16000, hard core K=3 (operator go). # [LEDGER 2026-09-10 @4.105.0] cell-m pilot (8 arms, n=4): `on` is BROKEN for DeepSeek planners as shipped — reasoning shares max_tokens (4000), so pro@low/high/max returned 0/10 lift plans + 1/8 resolver verdicts (blank after 50-75 s) and flash 3/10 + 2/9; every blank verdict fail-opened to MEETS. `none` = 8/8 plans, 12/12 verdicts, 5-9 s. STATUS: keep `none` (k=5 COMMON) until HB-MENTOR-BUDGET ships (max_tokens = content budget + reasoning allowance; finish_reason=length → retry thinking-off). Ledger .cortex/bench/r-cell-m-2026-09-10.md # CORTEX_MENTOR_CONSULT_REASONING — on|none. The AskForAdvice consult hint (400-token budget). Default none: the # 08-30 measurement — thinking-on hints came back BLANK (reasoning ate the budget); the m88 results were thinking-off. # [LEDGER 2026-09-10 @4.104.0] none (default) — unmeasured ON; opt in per cell. #CORTEX_MENTOR_CONSULT_REASONING=none # CORTEX_MENTOR_EFFORT — low|medium|high|max. ONE effort for every planner surface (the mentor-effort A/B lever); a # surface's own *_EFFORT (CORTEX_LIFT_PLAN_EFFORT etc.), when explicitly set, wins over it. Empty = per-surface (max). # [LEDGER 2026-09-10 @4.105.0] unset — cell-m A/Bs {pro, deepseek-flash} × {low, high, max} (+ thinking-off baselines). # [LEDGER 2026-09-11 @4.107.0] cell-n-r3 flash@low (REASONING=on): REJECT — delivery 91% thinking-on (the treatment fired) but false-accept 0.67 (worst measured; high 0.56, max 0.50, off 0.33) and 6/24 vs control 11/26. Effort is monotone in cost only; ANY thinking on the resolver raises false accepts. Moot while REASONING=none (k=5). DARK. Ledger r-cell-n-r34. # [LEDGER 2026-09-18 @4.119.1] TB4.0 cell e6, pro planner (resolver thinking-off in all arms, so this reached ONE call/session — the lift plan): control per-surface max 10/28 · low 9/29 (+3/−4) · high 12/29 (+5/−3, p 0.73, best point estimate, ~half of max's planner latency) · REASONING=none 11/29 (+3/−2, 10x faster lift). No level separates at n=29; candidate for the full run = high. Wire: max delivered thinking-on 5/5 @118–178 s; high 4/5 (+1 thinking-off retry) @60–158 s; low 3/5 (+2 retries) @53–84 s. # [LEDGER 2026-09-19 @4.119.1] FIELD, full TB4.0 (stack arm, =high): WASH vs per-surface max control (12/62 each); planner thinking-on 20/36 (16 retries) vs max 24/38 (14 retries). #CORTEX_MENTOR_EFFORT= # [LEDGER 2026-09-10 @4.105.0] cell-m pilot: low/high/max UNMEASURABLE — the thinking-on calls came back empty (see CORTEX_MENTOR_REASONING). Only flash@low ever delivered (1/4 plans, 2/3 verdicts). Re-test after HB-MENTOR-BUDGET. # CORTEX_ASK_FOR_ADVICE — true|false. Include the model-initiated AskForAdvice consult tool while mentorship is on. # =false drops it (and the forced-consult path) so a mentor effort/model A/B carries no consult confound. # [LEDGER 2026-09-10 @4.105.0] true (default) — the consult was measured thinking-off with weak voluntary heed (v1 0/6, # m88 auto-consult neutral); cells set false unless the consult is the thing under test. #CORTEX_ASK_FOR_ADVICE=true # CORTEX_MENTOR_TEMPERATURE — optional sampling temperature for mentor calls (0-2); empty = adapter default 0.7. #CORTEX_MENTOR_TEMPERATURE= # CORTEX_MENTOR_REASONING_ALLOWANCE — integer tokens. HB-MENTOR-BUDGET (4.106.0): DeepSeek counts reasoning tokens INSIDE # max_tokens, so a thinking-on mentor call sends max_tokens = content budget (e.g. 4000) + this allowance; empty = the # per-effort table low 4000 / medium 8000 / high 12000 / max 24000 (capped by the card's outputTokens). A thinking-on call # that still returns EMPTY content is re-issued ONCE thinking-off and the event banks truncated/retriedThinkingOff. # [LEDGER 2026-09-10 @4.106.0] BUILT from the cell-m pilot (0/10 pro lift plans, 1/8 verdicts at the 4000 cap; direct API: # completion_tokens 2045 = 1641 reasoning + ~400 content). UNTESTED on the bench — the flash-none vs flash-high re-pilot # (K=2) is the efficacy test; until then CORTEX_MENTOR_REASONING=none stays the k=5 COMMON. #CORTEX_MENTOR_REASONING_ALLOWANCE= # [LEDGER 2026-09-11 @4.107.0] cell-n-r1 at 16000 (cap 20K): flash@high/max still truncated ~30% (retry rescued, ~100 s); reasoningTok p90 16.8K/15.3K. Moot while thinking-on is DARK. # [LEDGER 2026-09-11 @4.106.1] cell-m-r1: flash@high thinking-on calls used 10.2K/10.6K reasoning tokens (med/p90) when they delivered and hit the 16K cap on 7/18 → 12K is ~50% short for flash@high; set 16000 on the next run (cap 20K). flash@max delivered at 3.8K/13.4K under 28K. # CORTEX_MENTOR_THINKING_TIMEOUT_MS — integer ms (4.106.2). A thinking-on mentor call (lift planner / EndTurn resolver / loop-exit # planner) races against max(surface timeout, this); the FIRST request is aborted at 60% of it so the thinking-off retry always # fits, and the event banks abortedFirstCall. Empty = per-effort table low 120000 / medium 180000 / high 240000 / max 300000. # [LEDGER 2026-09-10 @4.106.2] BUILT from cell-m-r1 (4.106.1): pro@high and flash@max reasoned past the 90 s surface timeouts → # banked deliveredBy=none (the retry never ran); flash@high delivered 6 thinking-on + 6 thinking-off-retry. UNTESTED on the bench. #CORTEX_MENTOR_THINKING_TIMEOUT_MS= # [LEDGER 2026-09-11 @4.107.0] cell-n-r1: 0 `none` deliveries (the wall is gone); pro@high aborted at 144 s (60% of 240 s) on 38/50 calls — pro cannot answer inside the first-call share on these prompts. Moot while thinking-on is DARK. # PER-SURFACE REASONING SWITCH (4.107.0) — on|none per mentor surface, wins over CORTEX_MENTOR_REASONING; empty = follow the # global lever. Built from the cell-m-r1 quality read (ledger §6): thinking-ON lift plans are task-specific/adversarial, the # thinking-OFF resolver is the strict judge (0 false accepts) — "planner on, resolver off" is the candidate config. # Also 4.107.0: the lift plan is handed to the resolver / deadline-exit / loop-exit judges as an ADVISORY anchor (the TASK wins # on disagreement); events bank liftPlanChars. # [LEDGER 2026-09-11 @4.107.0] BUILT; first bench test = cell-n-r1 arm `fh-plan` (CORTEX_LIFT_PLAN_REASONING=on + # CORTEX_ENDTURN_RESOLVER_REASONING=none under CORTEX_MENTOR_REASONING=none). #CORTEX_LIFT_PLAN_REASONING= # CORTEX_LIFT_PLAN_DOCTRINE — planner doctrine version: v1 (default; the 4.107.0 PLANNER_SYSTEM) | v2 (adds the four # cell-n-r1 census bullets: ONE INSTALL LAYER/uv, LONG WAITS ≤60 s polls, EXACT-OUTPUT byte-level, EXPECTED LITERALS ARE # LAW + graders re-parameterize). Prompt-only. # [LEDGER 2026-09-11 @4.107.2] LEVER (was hard-wired ON in 4.107.1). cell-n-r5 (4.107.1 control, hard core): 4/18 vs 11/26 on # 4.107.0, PAIRED 6 losses / 1 gain, fewer turns on 12/18 tasks (finishes earlier, less verification: gcode read "gcodo3" # without the control's max-zoom check). Shipped together with EndTurn essential, so attribution needs the 2×2 (cell-n-r6: # base / et-ess / doc-v2 / et-doc). Default v1 = measured baseline until the 2×2 decides. # [LEDGER 2026-09-11 @4.107.2] cell-n-r6 2×2: v2 8/26 vs v1 7/26 (standard tier), 7/26 vs 11/26 (essential tier); main effect 15/52 vs 18/52. Neutral to negative → v1 stays default; the doctrine-mine candidates (r5 §7) queue as a v3 arm. DARK. #CORTEX_LIFT_PLAN_DOCTRINE= # CORTEX_LIFT_PLAN_TOOL_ROUNDS / CORTEX_LIFT_PLAN_TOOL_ROUND_BUDGET_MS — R171 HB-LIFT-PLAN-TOOL-LOOP (4.118.0, 2026-09-18). The spec's # §2.2 v2 ("adaptive tool-using planner … so the mentor can cat a test file it just discovered"), built the R170 way: with ROUNDS > 1 # the planner persona + closing instruction offer `INVESTIGATE` + `CHECK: ` + `READ: [:a-b]`; the harness runs # them (isInvestigateCommandAllowed denylist, readFileSlice inside the workspace), appends an EVIDENCE block and asks again; the last # round withdraws the option; an INVESTIGATE after withdrawal = no plan (fail-open, the junior proceeds unplanned, banked as # investigateAfterWithdraw). Turn-capped, never token-capped (spec §2.4); aggregate ROUND_BUDGET_MS 240 s and never more than half of # the remaining wall budget. Why the planner and not (only) the judge: the judge's limit was self-authored evidence against a hidden # grader; the planner's limit is planning from a snapshot — and every later steering surface anchors to that plan. Event lift_plan += # {toolRounds, roundsUsed, investigateChecks, investigateReads, investigateRefused, investigateAfterWithdraw, roundLatencyMs, # evidenceChars}. Default 1 = 4.117.3 byte-for-byte. # [LEDGER 2026-09-18 @4.118.0] BUILT + unit-tested (liftPlanner.test.ts R171). FIELD 09-18 (arm lp, 4.118.1): DELIVERED + FULLY ENGAGED (12/12 sessions investigated, 47 checks + 36 reads), NULL — 1/12 = control; planner cost 2–9 min/task at pro/thinking-on → use the flash planner or ROUNDS=2 (ledger §10). #CORTEX_LIFT_PLAN_TOOL_ROUNDS= #CORTEX_LIFT_PLAN_TOOL_ROUND_BUDGET_MS= # [LEDGER 2026-09-11 @4.107.0] cell-n-r1 arm fh-plan (LIFT_PLAN_REASONING=on @high + resolver none): 7/25 vs control 10/24 — the thinking-on planner did not help on the hard core. DARK. # [LEDGER 2026-09-19 @4.119.1] FIELD, full TB4.0 (stack arm, =on @high, pro): thinking-on delivered 38/87 verdicts, 47/87 fell to the thinking-off retry (16K allowance exhausted); outcome WASH vs thinking-off control (12/62 each). #CORTEX_ENDTURN_RESOLVER_REASONING= #CORTEX_DEADLINE_EXIT_MENTOR_REASONING= #CORTEX_LOOP_TOOL_BLOCK_REASONING= # [LEDGER 2026-09-11 @4.106.2] evidence for the table: cell-m-r1 (4.106.1, 90 s surface): pro@high lift 0/7 delivered (all 91 s), resolver p90 90.9 s; flash@max 4/13 timed out. UNTESTED on the bench — first run on 4.106.2 must show abortedFirstCall + deliveredBy≠none on pro/max. # [LEDGER 2026-09-02 @4.90.0] ON — the VISION HAND-OFF (operator design): text-only primaries keep the ReadImage # tool; the orchestrator sends the image + the caller's `prompt` to this vision card THROUGH THE HELPER MIDDLEWARE # and returns TEXT (the primary never receives image bytes — item 7's safety intent holds). Evidence: in EVERY # image task of the c3/p3 cells (chess-best-move ×2, gcode-to-text, code-from-image ×2) the text model SEARCHED # for an image tool by name, found none, and hand-built tesseract/PIL pipelines that ate the budget. Same DeepSeek # key. Set false to restrict ReadImage to vision-capable primaries. # [LEDGER 2026-09-03 @4.90.1] ON — VALIDATED on the real bench (r-v4-validation-2026-09-03, n=1): fired HEAVILY # (flash 25 / pro 45 vision_handoff events) and drove flips — flash chess-best-move PASS (ReadImage×6, first flash-family # chess pass ever), pro dna-insert PASS (vis×6, p3-without-vision failed it), code-from-image PASS both models. Headline # k=5 lever. POST-RUN FINDINGS (audit of the 9 fails): (a) NO per-turn hand-off budget — gcode-to-text burned its whole # task budget on self-rendered slice reads (flash 14 / pro 34 ReadImage calls, never converged) → planned lever # VISION_HANDOFF_MAX (~8/turn) + a "consolidate into ONE labeled montage" reminder (def-fcb719427f); (b) structured # images misread — pro chess got a wrong whole-board transcription → bad FEN → nonsense move, while flash passed via a # montage of individually LABELED squares (def-a3e7920cf9): grid/crop-aware prompts beat whole-image reads; a stronger # vision card is the next lever once available. # [LEDGER 2026-09-10 @4.102.0] deepseek-flash — V4.1 Flash is multimodal; the vision-exp name is retired and routes here. VISION_HELPER_MODEL=deepseek-flash # Per-turn cap on ReadImage→vision-helper hand-offs (0 = unlimited). Past the cap ReadImage returns a # "consolidate your reads into ONE labeled montage / change approach" reminder instead of another vision call. # [LEDGER 2026-09-03 @4.91.0] ON=8 — ✅ v5 CERTIFIED: flash gcode-to-text fired vis×8 then vision_handoff_capped×2 (v4 was 14 uncapped) — cap bounds the runaway (gcode still fails: it is GEOMETRIC not OCR, vision is the wrong approach there). v4 gcode-to-text: 14 (flash) / 34 (pro) slice reads burned the whole task budget without converging (def-fcb719427f); chess flash passed with 6 reads. Cap event kind: vision_handoff_capped. Measure at k=5 (gcode budget_frac, chess flips). VISION_HANDOFF_MAX=8 # Periodic mentorship review every N turns MENTORSHIP_TURN_BASED_ENABLED=false # Turns between periodic reviews (1-50) MENTORSHIP_TURN_INTERVAL=10 # Inject thinking assistance for non-reasoning models MENTORSHIP_INTERLEAVED_THINKING=false # Detect and alert on repeated failure patterns. # ⚠️ PENDING DEPRECATION (backlog def-8ee006743f): superseded by the unified-outcome # layer (exact-input prior + family/approach lenses + near-dup breaker + auto-consult). # This legacy Phase-2 detector keys on RAW is_error, so it is BLIND to bash exit!=0 # retry-loops (the #1 class). Do NOT enable or extend it — leave false; slated for removal. # [LEDGER 2026-09-02 @4.89.0] DARK/DEPRECATING (def-8ee006743f) — superseded by the unified outcome classifier + lens path. Keep false; removal candidate. MENTORSHIP_PATTERN_DETECTION=false # Number of similar errors to trigger pattern detection (2-10). (Part of the pending- # deprecation MENTORSHIP_PATTERN_DETECTION feature above — no effect while that is false.) MENTORSHIP_PATTERN_THRESHOLD=3 # Post-turn summary + next-action prediction via the helper model # [LEDGER 2026-09-02 @4.89.0] DARK by design — interactive-only UX; repurpose as a mentor trigger = backlog def-940d3ffb2b (unbuilt). TURN_SUMMARY_PREDICTION=false # ============================================ # CONTEXT MANAGEMENT # ============================================ # Anthropic prompt caching (up to ~90% input-token savings) ANTHROPIC_PROMPT_CACHING=true # Context selection strategy is derived from the model card per-model # (compaction.behavior.compactOlder -> preserve-critical, else sliding-window) # and is not env-configurable. # Render prior thinking blocks as visible text on the # chat/completions path (recall for resumed reasoning-heavy sessions). THINKING_AS_TEXT_FALLBACK=false # ============================================ # SESSION CONFIGURATION # ============================================ # Where JSONL session files are written SESSION_STORAGE_DIR=.cortex/sessions # Auto-inject connected MCP servers' tools into every turn MCP_AUTO_INJECT=false # Auto-research subagents. off = disabled (PM never told; main context stays clean). # native = PM delegates to autoresearch-agent subagents that run experiments with the # internal tools. mcp = the subagents route experiment-running to the external # configured auto-research MCP server instead (MCP integration ships separately). Options: off, native, mcp AUTORESEARCH_AGENTS=off # Cap on bytes per injected project doc (CORTEX.md, MEMORY.md, etc.). 0 = unlimited. SYSTEM_MESSAGE_DOC_MAX_BYTES=0 # Archive-prune cap for MEMORY.md: when over cap, older overflow MOVES to a sibling # MEMORY.archive.md (never dropped) and MEMORY.md is bounded — fixes unbounded growth # + full-file injection without losing memories. 0 = off. ~10000 recommended. MEMORY_ARCHIVE_MAX_BYTES=10000 # ============================================ # LOOP CONTROL # ============================================ # Maximum tool executions per turn # [LEDGER 2026-09-02 @4.89.0] ON=1000 — failsafe not a work limit (the only guard that caught loops pre-ladder, expensively). MAX_TOOL_ITERATIONS=1000 # Stop the turn after this many consecutive all-error iterations # [LEDGER 2026-09-02 @4.89.0] ON=6 — 3 killed legitimate diagnosis mid-flight (train-fasttext specimen); the loop ladder owns graceful escalation. Part of the +11 guard stack (tb21g). MAX_CONSECUTIVE_ERRORS=6 # Soft per-turn tool-call budget (R29b brake: escalating reminders, hard cap at 2x) # 0 disables budget pressure entirely (R64) # [LEDGER 2026-09-02 @4.89.0] ON=400 — R64 default; 0 is a valid explicit value. TOOL_BUDGET_SOFT=400 # Per-tool execution timeout in milliseconds (2 minutes). With TOOL_TIMEOUT_MODE=auto this is the # PROMOTE threshold in headless sessions (the command keeps running in the background), the KILL # deadline in interactive ones. # [LEDGER 2026-09-02 @4.90.0] ON=120000 — p3 timeout audit (r-p3): the 120s kill fired 42× across 14 task-runs and RESCUED NONE (train-fasttext busy-wait driver, long builds); every p3 timeout was Harbor's budget, not ours. Kept at 120s because TOOL_TIMEOUT_MODE=auto promotes instead of kills in headless (item 8). v4 audit: pro/train-fasttext = the busy-wait driver again (249 bash, 22 cancels) and 4.90.0's promote was INERT (outer-abort race, fixed 4.90.1) → train-fasttext is the 4.90.1 re-test task. TOOL_TIMEOUT_MS=120000 # [LEDGER 2026-09-03 @4.91.0] ON=auto — ✅ v5 CERTIFIED FIRING on the real bench (tool_promoted: flash 2 / pro 2, on train-fasttext + dna-insert). 4.90.0 was INERT: the orchestrator's outer abort raced ShellTool's deadline and always won (v4 pro/train-fasttext: 22 cancelled, 0 promoted). 4.90.1: outer cap = TOOL_TIMEOUT_MS+30s, ShellTool default follows TOOL_TIMEOUT_MS; LIVE-VERIFIED (5s deadline, 9s command → tool_promoted event, model read the background output). Re-test task: train-fasttext. PROMOTE-AT-DEADLINE: when a Bash call exceeds TOOL_TIMEOUT_MS in a # headless/auto-approve session, the still-running command is moved to a background shell (bash_id) and the tool # returns the output so far instead of killing it; interactive sessions keep the kill. Evidence (c3/p3 trajectories): # the 120s kill fired 42x across 14 task-runs (19 legitimate scripts, 12 wait loops, 5 builds/trainings) and rescued # NONE of them — it only forced nohup+poll grinding (train-fasttext: 6-10 cuts/run, 20+ poll turns). kill|background # force a mode. Engagement evidence: decisions event steering_injected{kind:tool_promoted}. # [LEDGER 2026-09-13 @4.108.18] R142 HB-WAIT-PRIMITIVE (from Terminus 2's `{"keystrokes":"","duration":N}`): BashOutput gains `wait_seconds` (0-600, # returns early on new output / exit) and `wait_for` (regex; returns as soon as NEW output matches), result prefixed `[wait] , matched|output| # exited|timeout`; Bash persistentSession runs accept `wait_for` (tmux: capture polling after the echoed command; herdr: one combined # `pane wait-output --regex`), TmuxSession gains action `wait`; the R135 poll_steer text names them. Prefer wait_for over sleep polling. TOOL_TIMEOUT_MODE=auto # Identical tool calls before loop detection breaks the turn # [LEDGER 2026-09-13 @4.108.11] R137 HB-POLL-REPEAT-BREAKER: the breaker counted 5 identical `BashOutput {bash_id}` polls on a LIVE # background job as an infinite loop (TB4.0 validation mp-checkpoint-consolidation: turn force-exited at 42 min while the 580 s fit ran; the # banked toolCallIterations became 1000 = this cap value). Now: poll tools (BashOutput, InspectSandbox) count only when the RESULT is also # byte-identical and the process is not running; the exit uses an explicit loopBreak flag (true iteration count banked) + a `loop_break` # decisions row. Non-poll tools unchanged. MAX_LOOP_REPETITIONS=5 # Unified outcome ladder (4.70.0): failing near-duplicate approaches escalate # remind -> diversify -> graceful break (docs/UNIFIED_OUTCOME_LADDER.md). #LOOP_REMIND_AT=2 #LOOP_DIVERSIFY_AT=4 #LOOP_BREAK_AT=6 # Bench/server profiles: wrap bash commands with `set -o pipefail` so # `failing-cmd | tail` classifies as a failure instead of masking behind the # pipe's exit 0. NEVER default-on (changes user command semantics). # [LEDGER 2026-09-02 @4.89.0] ON — guard stack (tb21g attributable engaged net +11, help:harm 3.75:1). Was silently OFF for 5+ runs pre-CONFIG-AUDIT (adapter dropped it); adapter block and this file now diffed identical. CORTEX_BASH_PIPEFAIL=true # Lift the Bash $() command-substitution block entirely (sandboxed profiles, # e.g. bench containers — an OPERATOR decision; the check is a security # control). $(( )) arithmetic is never flagged regardless of this setting. CORTEX_ALLOW_CMD_SUBSTITUTION=true # Inaction guard (ladder's inverse, 4.70.0): one bounded "act first" retry on a # long actless first-turn response in a tool-capable request. Default OFF. # [LEDGER 2026-09-02 @4.89.0] DARK/unrun — act-first guard for zero-call verbose responses (pro-persist paralysis class); specced, never its own cell. #CORTEX_INACTION_NUDGE=false # Response length (chars) above which the inaction guard may fire. #CORTEX_INACTION_MIN_CHARS=4000 # ============================================ # PROVIDER TOOLING (server-side tools / API surface) # ============================================ # Inject server-side tools (web_search, x_search, code_execution) into XAI/OpenAI requests. # When true, overrides to the Responses API at request time regardless of XAI_API_MODE. # R37/R38 benchmarks: hybrid (true) is 20-26% faster than client-only with equal accuracy. ENABLE_SERVER_SIDE_TOOLS=true # Default API pattern for XAI models at registration time (ENABLE_SERVER_SIDE_TOOLS=true # overrides at request time). Options: messages | responses XAI_API_MODE=messages # OpenAI request surface. Options: chat/completions | responses (opt into hosted tools) OPENAI_API_MODE= # Only load essential tools initially; the model discovers the rest via SearchTools. # R43 benchmark: 77% input-token reduction on the first turn. # [LEDGER 2026-09-02 @4.89.0] ON — deferred-OFF (57 tools) broke a genuine control on vision (A′ matrix); 16-tool essential tier + SearchTools (dead every era until 4.88, now wired). Keep true. ENABLE_DEFERRED_TOOL_LOADING=true # A′ experiment (deferred-loading arm refinements — default OFF, opt-in per arm): # CORTEX_LIFT_NUDGE — at the anchor-lift boundary, append a ONE-LINE system-reminder # pointing the model at SearchTools (to reach the tools the deferred filter hides) and, # when mentorship is active, AskForAdvice. Turn 1 stays a pristine narrow door; the # pointer lands only after the model has acted. No-op when deferred loading is off. # GLOBAL BASELINE for models WITHOUT a card opinion (harness serves 17 models / 7 providers). # The per-model CARD OVERRIDES this (precedence: card > this env > default). ALL THREE deepseek # cards (flash/pro/vision) ship liftNudge:true — so this baseline NEVER touched the deepseek k=5 # reson run (card-forced true regardless of env). Where it DOES apply: un-carded providers # (grok / gpt / gemini / claude). It exists to compensate deepseek's boot-minimal preset, which # drops TOOL_USAGE_GUIDE so the model otherwise never learns discovery tools exist; models that # ship the full tool guide need it less. A card can still opt a specific model out. # [LEDGER 2026-09-06 @4.93.0] FLIPPED false->true (operator): extend the signpost fleet-wide. # TB2.1-NEUTRAL — deepseek is card-dominated so the bench is identical; this only newly enables it # for the un-carded non-deepseek providers (low-risk: a one-line SearchTools/AskForAdvice pointer). # Cross-model validation of these deepseek-tuned levers on other providers is PENDING (after TB2.1). CORTEX_LIFT_NUDGE=true # CORTEX_LIFT_PLAN — mentor-as-bounded-planner (LIFT_MENTOR_PLANNER spec). At the same anchor-lift # boundary, a bounded max-reasoning mentor plans the task ONCE: adversarial analysis of the prompt # + confirm the REAL grader criteria (not the model's own tests) + a criteria-anchored numbered # plan, or a RETIRE plan for a doomed task. Delivered as a system-reminder on the first tool_result # (orchestrator-direct-invoke — NOT a forced tool call, which DeepSeek ignores post-turn-0). The # narrow-door model resumes into the plan; the overthinking is quarantined in the mentor's single # bounded call. Targets the two measured failure classes: grind-to-wall (14/22 flash fails → RETIRE) # + self-graded success (5-7 convertible near-misses → criteria correction). Precedence: card > env > false. # Runs pro @ MAX reasoning (bounded single-shot planner can't grind → max is safe + best here). # INTERACTIVE GATE: fires only in headless/one-shot/bench sessions (autoApproveActions=true); in an # interactive TUI a ~30-60s silent pause reads as a frozen UI, so it is SUPPRESSED unless a thinking- # indicator is wired and CORTEX_LIFT_PLAN_INTERACTIVE=true. # Tuning (defaults chosen from the 2026-09-04 isolated eval): CORTEX_LIFT_PLAN_EFFORT (default max), # CORTEX_LIFT_PLAN_BUDGET_TOKENS (default 4000 — 🔴 at max reasoning a smaller budget is consumed # entirely by reasoning_content and returns an EMPTY plan: max+1200=0 chars, max+4000=clean 2727-char # plan; never token-cap tighter), CORTEX_LIFT_PLAN_TIMEOUT_MS (default 90000 — max reasoning took ~54s; # fail-open to no-plan on timeout), CORTEX_LIFT_PLAN_INTERACTIVE (default false), # CORTEX_LIFT_PLAN_RECON_TIMEOUT_MS (default 8000 — v1.1: before planning, the orchestrator runs a # bounded read-only ENV RECON (tooling present, installed pip/npm packages, disk/mem, test files) and # feeds it to the planner so it steers installs (uv/bun for MISSING packages, beyond bare boxes) and # per-step Bash timeouts from the box's REAL resources; fail-open to observations alone). # [LEDGER 2026-09-04 @4.91.1] BUILT DARK / FIRE-CHECKED — v1 shipped gated-off (typecheck clean, planner tests, orchestrator e2e 26/26 no-regression, core build clean). LIVE FIRE-CHECK PASSED (lift_plan event fired:true/planChars>0/criteriaStated:true; negative control clean). ISOLATED EVAL: plan quality EXCELLENT at max+4000 (criteria-anchored, adversarial, anti-self-test) — but caught max+1200=empty (defaults bumped to max/4000/90s). Still UNTESTED for pass-rate lift: needs the treatment bench (grind-retire + criteria-misalign score-lift) BEFORE trusting efficacy. Adapter must add these to its env passthrough or the bench arm runs dark. Keep false. # [LEDGER 2026-09-06 @4.93.0] ON (reson standard baseline). Part of the reson stack (GATE+REQ+LIFT+RESOLVER) that shipped through resolver-k5 (proven net-positive as a stack). NOTE: k5 held LIFT on in BOTH arms (shared baseline, not the A/B variable) — its independent efficacy stands from the 2026-09-04 isolated eval (plan quality excellent at max/4000); k5 ratifies the reson stack as standard, not LIFT in isolation. # [LEDGER 2026-09-11 @4.107.1] PLANNER DOCTRINE +4 bullets (HB-PLAN-DOCTRINE, cell-n-r1 census): ONE INSTALL LAYER (uv owns venv+packages / bun / reuse what is present — no python→.venv→python stacks), LONG WAITS (background + poll ≤60 s, no minute-long sleeps), EXACT-OUTPUT (byte-level, never parse→re-serialize), EXPECTED LITERALS ARE LAW + graders re-parameterize (derive at run time, never bake constants). Prompt-only; efficacy = next hard-core run on 4.107.1 vs cell-n-r1 flash-none 10/24. Same release: EndTurn discoveryTier standard→essential (HB-ENDTURN-TIER, not a lever). CORTEX_LIFT_PLAN=true #CORTEX_LIFT_PLAN_EFFORT=max #CORTEX_LIFT_PLAN_BUDGET_TOKENS=4000 #CORTEX_LIFT_PLAN_TIMEOUT_MS=90000 #CORTEX_LIFT_PLAN_INTERACTIVE=false #CORTEX_LIFT_PLAN_RECON_TIMEOUT_MS=8000 # CORTEX_ENDTURN_RESOLVER — the finish-side twin of the lift planner: AFTER the mechanical EndTurn gate # accepts, a bounded max-reasoning mentor adjudicates "does the work product meet the task's real # requirements?" MEETS finishes; GAP vetoes with a fix plan (the narrow-door model executes it instead of # reasoning its way out of a mechanical rejection). Reuses the lift planner's env recon. Recommended # pairing: GATE + RELAXED + resolver — the smart wrong-artifact judgment strict reached for, minus strict's # bugs (likely makes strict unnecessary). Interactive-gated (same as the lift planner). Precedence card > env > false. # Tuning: CORTEX_ENDTURN_RESOLVER_EFFORT (max), CORTEX_ENDTURN_RESOLVER_BUDGET_TOKENS (4000), # CORTEX_ENDTURN_RESOLVER_MAX_REJECTS (2 GAP vetoes → then fallback-accept, liveness), CORTEX_ENDTURN_RESOLVER_TIMEOUT_MS (90000). # [LEDGER 2026-09-04 @4.92.0] BUILT DARK — mentor-as-EndTurn-judge; tsc clean, 8/8 resolver tests, orchestrator e2e 26/26 no-regression, eval-validated (caught a missing-NOT_FOUND self-graded pass + passed a correct finish). UNTESTED for pass-rate: the treatment bench = resolver ON vs OFF (both on relaxed). Keep false. # [LEDGER 2026-09-06 @4.93.0] 🟢 PROVEN NET-POSITIVE + ON (reson = the new STANDARD). resolver-k5 (11-task×5, flash primary + pro@max mentor, resolver ON vs OFF): 5 help / 0 hurt, aggregate 75.5% vs 58.2% (+17pp), cost-neutral-to-cheaper ($0.116/task avg). Judgment quality HIGH (specific correct requirement-gap rejects; reject→retry→pass confirmed in decisions.jsonl); 4 resolver-attributable helps. Open v2 (gating, not verdict text) = coverage(fallback branch) + abstention(over-fires on hopeless). See .cortex/bench/resolver-k5-2026-09-06.md. CORTEX_ENDTURN_RESOLVER=true #CORTEX_ENDTURN_RESOLVER_EFFORT=max #CORTEX_ENDTURN_RESOLVER_BUDGET_TOKENS=4000 #CORTEX_ENDTURN_RESOLVER_MAX_REJECTS=2 #CORTEX_ENDTURN_RESOLVER_TIMEOUT_MS=90000 # CORTEX_ENDTURN_RESOLVER_ABSTAIN — offer the judge a third verdict, RETIRE, for a structurally # UNCLOSABLE finish (missing capability, wrong-approach loop, impossible constraint) and HONOR it: # accept the finish + STOP the reject cycles instead of burning pro@max re-rejecting a task the # junior can't fix. Confidence gate is in the prompt (when in doubt → GAP). Ships DARK. # [LEDGER 2026-09-06 @4.93.0] DARK/PENDING — built (resolver v2 abstention axis); addresses the k=5 # over-rejection finding (filter-js 7 rej/0 pass, pytorch 8 rej/1 pass). NOT yet validated live — # arm in the next fanout cell (measure cost-per-PASS + false-RETIRE rate vs resolver-without-abstain). # [LEDGER 2026-09-07 @4.94.0] DARK/PROMISING (n=1, dark-levers dlabs vs dlctl): equal pass (7=7), # ~30% CHEAPER ($1.53 vs $2.32), MECHANISM-ATTRIBUTABLE — decisions.jsonl shows abstain/RETIRE fired # on the reject-loop tasks (filter-js abstain×2/retire×3, pytorch abstain×1, sqlite-gcov abstain×1). # Thesis confirmed (stops burning pro@max re-rejecting doomed finishes). # [LEDGER 2026-09-07 @4.94.0 — SHIP-ON, operator decision] 🟢 ON (reson STANDARD). Flipped default-on # from the n=1 PROMISING verdict (equal pass, ~30% cheaper, mechanism-attributable). Rationale # (operator): affirm-then-verify, not gate-then-ship — budget doesn't allow adversarially EXCLUDING # a promising optimization vs AFFIRMING it. k=5 now CONFIRMS rather than gates (pins the published # version → re-measures ABSTAIN on current code). Orthogonal to this session's other changes: the # resolver/adjudicateEndTurn path reads task/env/workProduct/attestation only — NO classifyToolOutcome/ # failure-count/loop-block coupling (grep-verified); loop-block ships dark (no-op); distiller = tooling. # ROLLBACK if k=5 shows a net regression or a high false-RETIRE rate. CORTEX_ENDTURN_RESOLVER_ABSTAIN=true # CORTEX_JUDGE_DELTA / CORTEX_JUDGE_RUN_CHECK — HB-JUDGE-GROUNDING (2026-09-10): the done/not-done judges (EndTurn # resolver, deadline exit planner) receive the ARTIFACT: a bounded workspace delta (files changed this task + heads), # a FRESH environment recon at judge time (was a cached start-of-task snapshot), the LATEST tool outputs (was the # oldest 4K), and — resolver only — the result of an evident check entry point (Makefile test / test.sh / pytest) run # by the harness. The judge prompts already demanded an adversarial check against the task's real criteria; this # delivers the evidence they assumed. _CHECK_TIMEOUT_MS caps the check run; _DELTA_MAX_FILES / _DELTA_HEAD_LINES bound # the delta. # [LEDGER 2026-09-10 @4.101.0] ON (defaults true) — cell-d-k3: resolver held 9/10 PASSING finishes, exit planner mis-called # 3/3 real done/not-done decisions, both judging prose + a stale inventory. Efficacy = the next finishing-population cell # (metrics: false-hold rate on passing rows, hold-driven flips, exit-planner mis-calls). =false restores the old inputs. #CORTEX_JUDGE_DELTA=true #CORTEX_JUDGE_RUN_CHECK=true #CORTEX_JUDGE_CHECK_TIMEOUT_MS=45000 #CORTEX_JUDGE_DELTA_MAX_FILES=8 #CORTEX_JUDGE_DELTA_HEAD_LINES=60 # # CORTEX_EMPTY_TURN_CONTINUE — the HB-ENDTURN-TERMINAL fix (operator design 2026-09-08). The EndTurn # gate's terminal "you stopped — write your answer, do NOT call any tools" reminder can fire on a # reasoning-only mid-recon turn (the model thought but emitted no tool call yet), forbidding recovery # and cutting a build one turn short — the dominant DeepSeek premature-surrender pattern. When on, a # reasoning-only empty turn that STILL HAS BUDGET (<60% of the per-turn wall-clock deadline AND <60% of # max tool-iterations) is classified `reasoning_only_active` (mirrors the D-E `truncated` carve-out) and # gets a bounded (×3) "continue with tools — you still have budget" nudge instead of the terminal # surrender. Applies to both the non-stream and stream loops (stream reuses the EndTurn gate's # re-request mechanism). NOT the loop-block lever (proven: the terminal reminder fires in control arms; # loop_tool_block fired 0× in k5v2). Flag off = byte-identical. # [LEDGER 2026-09-08 @4.96.1] DARK (default false) — BUILT + tsc-clean + emptyResponseClassifier 19/19 + # emptyTurnContinue integration 4/4 (both loops flag-on continue+resume, flag-off terminal, budget-spent # regression guard) + reexecutionGuard regression check. Ships dark; efficacy A/B still owed. #CORTEX_EMPTY_TURN_CONTINUE=true # # CORTEX_DEADLINE_EXIT_MENTOR — the "smart deadline". At the WARN rung (~0.9 of the per-turn # wall-clock deadline, where residual still exists), a bounded mentor decides what to do with the # time left: CONTINUE (on-track/closing-in — let it run; do NOT truncate a late win), FINISH # (already meets criteria → end now), ACTION (one minimal step closes it → inject + finish), or # RETIRE (stuck/unclosable → end cleanly). Replaces the dumb "wrap up" nudge; the hard-floor break # at the deadline stays as the failsafe. Residual-scaled call budget (never eats the residual it # preserves). Tuning: _EFFORT (max), _BUDGET_TOKENS cap (2000), _TIMEOUT_MS cap (45000), # _RESIDUAL_FRAC (0.4 of remaining ms). # [LEDGER 2026-09-06 @4.93.0] DARK/PENDING — built (abnormal-exit/deadline fix; the properly-scoped # deadline adjudication, NOT the mis-premised endturn_gate_fallback). Addresses budget_frac>1.0 # overrun + last-fifth grind. 🔴 quality-gated (tell "closing in" from "grinding") — arm in the next # fanout cell; measure pass-rate + budget_frac on the 0.80-1.0 finishing population. # [LEDGER 2026-09-07 @4.94.0] DARK/RE-TARGET (n=1, dark-levers dldln): FIRED (make-mips×2, schemelike×1) # but its only +1 flip (pytorch) was on a task where it did NOT fire = noise; no attributable gain, # +cost (59 turns). Its "don't-truncate-late-win" value needs the 0.80-1.0 FINISHING population # specifically, not this reject-loop-heavy subset. ⇒ keep dark; re-target the k=5/next cell to the # high-budget_frac finishers (schemelike/make-mips/install-windows/filter-js/pytorch). Stays false. # [LEDGER 2026-09-10 @4.99.0] DARK/RETIRED-FOR-k5 (cell-d-k3: k=3, 2×2 flash+pro × ctl/lever, 42/42 rows on the # FINISHING population make-mips/pytorch/schemelike/filter-js (+gcode pro), STDB spine): FIRES (8/18 deadlined lever # rows; pro 5/8) but 0 attributable flips — every fired row failed except schemelike (passes on ctl). Flash +0.17 = # pytorch variance on rows that never fired; pro −0.11 = ctl finished make-mips LATE at 0.91 and the lever cut its twin # off at 0.90/0.94. Fired pro rows still end at ~1.0 budget (the mentor exit eats ~10%; 1 AgentTimeoutError). Only win: # pro tokens −24%. ⇒ stays false; not in the TB2.1 k=5 COMMON. Re-open only with a cheaper exit + ≥0.95 / progress-aware # trigger. Ledger omniclaude-v4/.cortex/bench/r-cell-d-k3-2026-09-10.md. #CORTEX_DEADLINE_EXIT_MENTOR=false #CORTEX_DEADLINE_EXIT_MENTOR_EFFORT=max #CORTEX_DEADLINE_EXIT_MENTOR_BUDGET_TOKENS=2000 #CORTEX_DEADLINE_EXIT_MENTOR_TIMEOUT_MS=45000 #CORTEX_DEADLINE_EXIT_MENTOR_RESIDUAL_FRAC=0.4 # CORTEX_HEADLESS_DROP_ASKUSER — in NON-INTERACTIVE sessions (stateless /v1/messages, # headless API, piped oneshot) there is no human to answer AskUserQuestion, so it is a # stall trap; drop it at the tool source. Kept in interactive TUIs. # GLOBAL BASELINE for un-carded models; the per-model card overrides (precedence: card > env > # default). ALL THREE deepseek cards ship headlessDropAskUser:true — so this baseline never touched # the deepseek k=5 reson run. Where it applies: un-carded providers (grok/gpt/gemini/claude). Only # fires in NON-INTERACTIVE sessions (stateless /v1/messages, headless API, piped oneshot) where no # human can answer AskUserQuestion — interactive TUIs always keep the tool. # [LEDGER 2026-09-06 @4.93.0] FLIPPED false->true (operator): drop the stall-trap tool fleet-wide in # headless. TB2.1-NEUTRAL (deepseek card-dominated); only newly affects un-carded non-deepseek # providers in headless. Cross-model validation PENDING (after TB2.1). CORTEX_HEADLESS_DROP_ASKUSER=true # Programmatic Tool Calling (compose tool calls in a script) — experimental # [LEDGER 2026-09-02 @4.89.0] DARK/N/A — Anthropic-only server-side code execution; not on the DeepSeek path. ENABLE_PTC=false # Allow local code-execution tooling ENABLE_LOCAL_CODE_EXECUTION=false # ============================================ # MODEL ROUTER (auto model selection) # ============================================ # Auto-select a model based on task type + benchmark history (routes model="auto") MODEL_ROUTER_ENABLED=false # Routing strategy: auto (classify the prompt) | matrix-only (require explicit task type) MODEL_ROUTER_STRATEGY=auto # Record turn metrics to .cortex/router-matrix.jsonl (independent of routing being enabled) MODEL_ROUTER_RECORD=false # Models the router must NEVER auto-select (cost/policy bans), comma-separated. # A trailing '*' is a prefix wildcard: 'grok*' excludes EVERY xAI model (present and # future) so exploration can never route a sub-agent to a grok model — honors the # standing cost constraint. MODEL_ROUTER_EXCLUDE=grok* # Opt-in explore/exploit (Thompson sampling) for model='auto'. OFF = conservative greedy # trust-gated routing. ON = posterior-sample each model and route to the sampled-argmax, # so thinly-sampled models get a chance and the matrix stops being self-confirming. MODEL_ROUTER_EXPLORATION=false # Trust gate for sub-agent model='auto' dispatch (works even when ENABLED=false — passing # 'auto' is the orchestrator's explicit per-dispatch opt-in): # Min task-classification confidence (0-1) before 'auto' routes; else inherits parent model ROUTER_MIN_CONFIDENCE=0.3 # Min real benchmark samples a task type needs before 'auto' trusts the matrix # recommendation; else inherits parent. Met as MODEL_ROUTER_RECORD accumulates data. ROUTER_MIN_SAMPLES=3 # ============================================ # END-OF-TURN AUDIT / TRAINING SUBSTRATE (opt-in) # ============================================ # Mandatory EndTurn pre-delivery self-audit + Stage 2/3 verifiers. Default OFF; ON = # graded cortex-channel training records (the tool is hidden when off). # [LEDGER 2026-09-03 @4.91.0] DARK/PENDING → **RECOMMENDED ON for k=5 (with REQUIREMENTS=strict)** — 4.91.0: gates now run on the STREAMING path too (were sendMessage-only; one shared endTurnGates.ts, live-proven on stream:true) and Stage-2 grounding accepts text the model WROTE this turn (Write/Edit content) — the false 'not grounded' rejections on authored files are gone. COST (v4 pass mining + doctrine-mine): every pass paid 4-8 EndTurn round-trips, the biggest share = Stage-2 CITATION rejects (17/43 doctrine findings; the model never re-ran a command for a fresh verbatim line) → 4.90.2 nudge teaches per-turn grounding + re-run; expect controls' +25-35% turn tax to drop — measure at k=5. — v4 (n=1, @4.90.0): gate engaged heavily under strict (flash gate_req=22/cite=13, pro 17/4), controls bn-fit+sqlite held on BOTH models, pro flips vs p3: dna-insert, pytorch-model-cli, cancel-async (n=1 candidates). Prior 3 cells: 4.71 fp 11→1 · fd +2/5 · c3 (n=2, r-c3-candidate-config) code-from-image FLIP 2/2 (first flash-family pass ever; Stage-4 requirement rejections, no mentor) + dna-insert 1/2; 0 clean regressions outside its LIMIT (accepts a re-attested wrong artifact: pytorch-model-cli r2, dna-insert fd). Cost: attestation turns. Operator decision pending. PRO (r-p3, n=1): controls 3/3 held with NO attestation tax (bn-fit 53→30 turns), 0 regressions, 0 paralysis; 0/13 flips on pro's hard core (budget timeouts while working). → k=5 config for BOTH models: guards + GATE+REQ + ENABLE_WEBTOOLS=false, mentor/tail off. # [LEDGER 2026-09-06 @4.93.0] ON (reson standard baseline). GATE+REQ (with REQUIREMENTS=true, NOT strict) shipped as the shared reson baseline through resolver-k5 — proven net-positive as a stack. k5 held GATE on in both arms; prior cell evidence stands. Part of the standard. CORTEX_ENDTURN_GATE=true # CORTEX_ENDTURN_TIER — EndTurn discovery tier: essential (DEFAULT since 4.107.3; in the turn-1 tool set, no SearchTools # hunt for the mandatory finish tool) | standard (deferred behind SearchTools; the 4.107.0 baseline, for A/Bs). # [LEDGER 2026-09-11 @4.107.2] LEVER (was hard-wired essential in 4.107.1 after the cell-n-r1 census: 70–80% of sessions spent a # SearchTools call hunting EndTurn, 11 tried Task as a finish tool). MECHANISM PROVEN on cell-n-r5: SearchTools 21→2, Task 3→0 — # but the hard core REGRESSED (4/18 vs 11/26) with fewer turns per task: a more salient finish tool may end turns EARLY. # Shipped with the planner doctrine, so the 2×2 (cell-n-r6) attributes it. Default standard = baseline until then. # [LEDGER 2026-09-11 @4.107.2] cell-n-r6 2×2 (hard core, n=26/arm): essential 11/26 vs standard 7/26 (same doctrine), main effect 18/52 vs 15/52, paired +7/−3; equals the best control. → k=5 runs with CORTEX_ENDTURN_TIER=essential (K5_EXTRA_COMMON); code default flips to essential in the next release if k=5 n=1 confirms. r5's 4/18 was variance + 8 lost rows, not this lever. # [LEDGER 2026-09-11 @4.107.2] tb21-k5-n1 (FULL 89, K=1, flash, essential via K5_EXTRA_COMMON): 70/89 = 78.7% (prev flash best 67/89), $2.81 off-peak, SearchTools 3/88 tasks, resolver false-accept 0.04. → CODE DEFAULT flips to essential in the next release (k=5 n=1 confirms). # [LEDGER 2026-09-11 @4.107.3] DEFAULT FLIPPED to essential (code); empty = essential. standard stays available for baselines. # [LEDGER 2026-09-11 @4.107.2/4.107.3] k=5 SERIES (TB2.1 full 89 × 5 sequential runs, essential + doctrine v1 + mentor flash/none): 70/71/65/70/68 → pass@1 mean 77.3% (sd 2.7), pooled 344/445; SearchTools ≤5 calls/run. CONFIRMED as default (4.107.3). Installed-DSH control on the same substrate = 71/89 (79.8%), published 90.6 not reproduced. Ledger .cortex/bench/r-tb21-k5-series-2026-09-11.md #CORTEX_ENDTURN_TIER= # CORTEX_COMPACTION_RESUME — resume memory across PROACTIVE compaction (4.108.0, HB-COMPACTION-RESUME). Before 4.108.0 the orchestrator # silently DROPPED the oldest message groups at the compaction threshold (~747K tokens on a 1M card) — no summary, no event, no trace, # and the task statement itself could be lost. true (default): the helper model summarizes the dropped messages into a resume memory, # the original task is pinned verbatim, both are prepended as a , a `compaction` event lands in decisions.jsonl, the # reminder is appended to the session JSONL, and .cortex/memory/resume-.md is written. false = the old silent drop. # [LEDGER 2026-09-12 @4.108.0] BUILT + unit-tested (compactionResume.test.ts); UNMEASURED on a bench — the first TB4.0 (8-h budget) run on # 4.108.x is the field test (count `compaction` events per session; compare pass rate on tasks that compacted vs the 4.107.2 VM run). # [LEDGER 2026-09-12 @4.108.3] LIVE-PROVED (forced 14K threshold, deepseek-flash, /tmp/claude-1000/cmp-test/run.sh): reminder + verbatim task # pin + rebuild protocol on every compaction; resume file written; facts survived 6 compactions (4/4). The hardened proof (task working set # > window) found the v2 stale-checkpoint replay (fixed, v3 rolling memory) and that the anti-loop stack fights chunked reads # (HB-CHUNKED-READS, open) — a task whose working set exceeds the window still degrades; that is the model's problem class, not this lever's. #CORTEX_COMPACTION_RESUME= # CORTEX_COMPACTION_CHECKPOINT_PCT / _STEP — the PRESSURE RUNG (4.108.2): the resume memory of the WHOLE conversation is written by the # helper model at PCT (default 0.75) of the compaction threshold — BEFORE any drop, the way the operator's resume-session routine checkpoints # at ~85% of the window — and refreshed every STEP (default 0.10). At compaction a checkpoint younger than 15% of the threshold is reused # (no second helper call); otherwise the dropped messages are summarized. The memory uses the resume-session template (WORK ORDER verbatim, # DONE, OUTSTANDING with next commands, DECISIONS/REJECTED, ARTIFACTS, TRAPS, CURRENT WORK) and the reminder ends with the REBUILD PROTOCOL. # [LEDGER 2026-09-12 @4.108.2] BUILT + unit-tested (compactionResumeTemplate.test.ts); UNMEASURED on a bench — field read = `compaction` events # with mode checkpoint|proactive and memorySource checkpoint|dropped per session on the first 4.108.2 TB4.0 run. # [LEDGER 2026-09-12 @4.108.3] v3: reuse is gated on COVERAGE (the checkpoint summarized every dropped message), else the prior memory is # ROLLED forward with the dropped messages (memorySource `rolled`); the rung RE-ARMS after each compaction so the last band before the # threshold refires every cycle (one whole-conversation helper call per cycle). Live: 28 compactions / 28 fresh covering checkpoints / # 0 stale replays (proof run 6). The v2 rule (token distance) replayed ONE stale memory into 27 compactions — never ship a reuse test on tokens. # [LEDGER 2026-09-13 @4.108.8] R132 HB-COMPACTION-ESTIMATE: the estimator is now ANCHORED on the provider's last reported prompt_tokens # (+ chars/4 of what was appended since; proportional shrink after a drop) — the chars/4-of-the-JSON-envelope heuristic (R129-scaled) is only # the fallback before the first usage arrives. Field read on the TB4.0 definitive run (4.108.5): heat-pump-warranty compacted at "760K-1.0M" # vs an API max of 151,763 prompt tokens (5-7x over). Compaction rows now bank estimateSource usage-anchored|heuristic + anchorTokens. # CORTEX_COMPACTION_HANDOFF_QA / _MAX_QUESTIONS — R143 HB-HANDOFF-QA-SUMMARY (4.108.19), from Terminus 2's three-step handoff: after the checkpoint # memory is written, (2) a history-FREE helper call is given the task + the summary + the workspace state and asks up to N gap questions a # successor would need answered; (3) a helper call WITH the covered history answers them (verbatim values; "not recorded" when unknown); the # memory gets a `## GAPS (Q/A)` section. Banked on the compaction row as handoffQA {questions, answered, notRecorded, cost}; any failure keeps # the plain memory. DARK (default false) — an A/B on the compaction proof task decides it (rig must be rebuilt; recipe in the 4.108.3 lines). # [LEDGER 2026-09-13 @4.108.19] BUILT + unit-tested (compactionResume.test.ts 28, effectiveConfig-handoffQA 2); UNMEASURED. Known gap: the helper # adapter's chunking path ignores the prompt override on oversize histories (answers degrade to "not recorded"). #CORTEX_COMPACTION_HANDOFF_QA= #CORTEX_COMPACTION_HANDOFF_QA_MAX_QUESTIONS= #CORTEX_COMPACTION_CHECKPOINT_PCT= #CORTEX_COMPACTION_CHECKPOINT_STEP= # CORTEX_COMPACTION_THRESHOLD_TOKENS — TEST/OPS OVERRIDE of the compaction threshold (4.108.3). Unset (default) = the threshold is derived # from the model card's context window (the ~747K/1M rung). Set = that many tokens becomes the compaction threshold and the kept-history # budget is half of it, so the whole compaction path (checkpoint rung → helper resume memory → proactive drop → reminder + rebuild protocol) # can be exercised in minutes on a small task instead of after hours of an 8-h bench task. NOT a tuning lever for production: a low value # discards history the model still needs. The resume memory is sized to ~10% of the threshold (clamp 1500–6000 tokens) so a small threshold # does not produce a memory larger than the history it replaces. # [LEDGER 2026-09-12 @4.108.3] BUILT + unit-tested (compactionResume.test.ts: resumeMemoryTargetTokens, resolveTaskText); used by the LIVE # proof (/tmp/claude-1000/cmp-test/run.sh, deepseek-flash, threshold 14000, rung 0.6): checkpoint fired, 6 proactive compactions in 17 # iterations (5 reused the checkpoint at $0), task pinned verbatim in every reminder, final answer 4/4 planted facts — mechanism proven. #CORTEX_COMPACTION_THRESHOLD_TOKENS= # CORTEX_STATE_DIR — explicit runtime-state root (4.108.6, HB-READONLY-WORKDIR / R131). Unset (default) = /.cortex, but the root # is PROBED for writability once per project: a read-only or foreign-owned working directory (a task image that runs the agent as `nobody` # in a root-owned /app) falls back to ~/.cortex/projects/, then /nexus-cortex/, with ONE warning. Every runtime writer # (tmux metadata/locks, artifact registry, sessions, decisions.jsonl, training samples, resume memory) routes through it, so state # persistence is never a boot precondition. Set it to pin the root explicitly (containers, benches, shared checkouts). # [LEDGER 2026-09-12 @4.108.6] BUILT + unit-tested (utils/__tests__/stateDir.test.ts); field cause = TB4.0 risk-scorer-replay: cortex-server # died at boot (EACCES mkdir /app/.cortex/tmux-sessions/metadata) → empty session. Verify = boot the server as an unprivileged user in a # root-owned cwd (docker probe) → boots with the fallback warning. #CORTEX_STATE_DIR= # CORTEX_DELEGATION_HINT — DARK (4.108.1, HB-DELEGATION-DOCTRINE). true = the boot-minimal prompt gains ONE clause naming the Task tool for # large / independent / output-heavy sub-tasks (delegate with a self-contained prompt, continue from the summary). The Task tool is # essential-tier but the bash-edit anchor strips it on turn 1 and the ~400-byte door never mentions it — 0 Task calls in every bench run # to date. Every Task dispatch now banks a `task_spawn` decisions.jsonl event regardless of this lever (mechanism-engagement evidence). # [LEDGER 2026-09-12 @4.108.1] BUILT + unit-tested (delegationHint.test.ts); DARK — prompt mass on the narrow door is a measured lever, so it # needs an A/B on the long-horizon population (TB4.0) before any default. Field read = task_spawn count per session. #CORTEX_DELEGATION_HINT= # CORTEX_SUBAGENT_TIMEOUT_MS / CORTEX_SUBAGENT_TIMEOUT_MAX_MS — R133 HB-SUBAGENT-TIMEOUT (4.108.8). The Task sub-agent's wall-clock limit was a # hardcoded 300 s regardless of the parent's budget: on the TB4.0 definitive run 3 of 6 delegates were cut at 300.0 s (one after 62 turns and # 6 files modified, the parent redid the work). Now: the Task input `timeout_ms` wins (clamped to [60 s, remaining-30 s]); else a parent turn # deadline (CORTEX_TURN_DEADLINE_MS, set per task by the bench adapter) gives 90% of the REMAINING budget minus 30 s, capped by # CORTEX_SUBAGENT_TIMEOUT_MAX_MS if set; else CORTEX_SUBAGENT_TIMEOUT_MS; else 300000. The child receives the same limit as ITS turn deadline # only when a real deadline exists. A TIMEOUT result still carries the partial response + Files Modified (inspect on-disk state, don't redo). # The outer per-batch abort now honors the resolved Task/Browse limit (it was a Bash-only 150 s cap that killed delegates first). # task_spawn decision rows bank timeoutMs[] + remainingMs. Unset = derived as above. # [LEDGER 2026-09-13 @4.108.8] BUILT + unit-tested (subAgentTimeout.test.ts, outerToolTimeout.test.ts); validation cell = the 3 TB4.0 tasks # whose delegates timed out (mp-checkpoint-consolidation, retro-console-soc, vllm-deepseek-streaming) — PENDING. #CORTEX_SUBAGENT_TIMEOUT_MS= #CORTEX_SUBAGENT_TIMEOUT_MAX_MS= # CORTEX_OUTER_TOOL_TIMEOUT_MS — R133b (4.108.10): FLOOR (ms) for the orchestrator's outer per-batch tool abort. The abort was # TOOL_TIMEOUT_MS (120 s) + 30 s grace = 150 s and honored only Bash's requested timeout (TB2.x fix) — every other tool was killed at 150 s: # the TB4.0 definitive run shows 5 `Tool execution timeout after 150000ms` (3 Task delegates mid-turn, 2 CreateArtifactTool persistent # launches in ctr-optimization). R133 made Task/Browse contribute their own limit; this lever floors everything else: # deadline = max(computed, floor) + grace. Unset = no floor (byte-identical to before). Bench COMMON under an 8-h budget: 600000. # [LEDGER 2026-09-13 @4.108.10] BUILT + unit-tested (outerToolTimeout.test.ts floor table; effectiveConfig registration). Not yet in a run. # [LEDGER 2026-09-14 @4.108.20] FIELD-VALIDATED in tb4-flash-v2 (63 tasks @600000): 0 outer-abort kills (v1 without the floor: 5). #CORTEX_OUTER_TOOL_TIMEOUT_MS= # CORTEX_API_NETWORK_RETRY_MS — R150 HB-API-CONNECTION-RESILIENCE (4.108.20): wall-clock BUDGET (ms) for retrying NETWORK-CLASS API faults # (OpenAI-SDK "Connection error.", undici "terminated"/"other side closed", ECONNRESET, 5xx) on an exponential ladder capped at 60 s per wait. # Before: those two SDK messages were not in ErrorClassificationMiddleware's network list → not retryable → RetryMiddleware threw on attempt 1 → # the tool loop exited → the R29a synthesis also failed → `endturn_gate_fallback abnormal-exit-bypass` shipped the turn. tb4-flash-v2: a ~2-min # transport blip at 8:36 AM PT 09-14 ended 3 lanes at once (wdm-design at iteration 141 mid-optimization — v1 PASSED it at 409 min; uefi-bootkit # 255; vpp-loss-divergence 8) + formal-crypto earlier; v1 had zero. Even a retryable class was 3 attempts ≈ 7 s. Default 600000 (10 min); # 0 = legacy attempt cap. Rate limits keep their own lower cap. The bypass event now banks the error text (detail.error). # [LEDGER 2026-09-14 @4.108.20] BUILT + unit-tested (ErrorClassificationMiddleware.test.ts R150 shapes; RetryMiddleware.test.ts budget ladder). # Companion R149 HB-COMPACTION-IMAGE-CHARS (same release, no lever): compactionResume approxCharsOf flattens base64 image payloads to # IMAGE_BLOCK_CHARS (6000) — the chars/4 growth term counted a 1 MB screenshot as ~250K tokens → 3 false proactive compactions in tb4-flash-v2 # (estimates 826K–969K vs API 14K–318K; every one an image-heavy session). unit-tested (compactionResume.test.ts R149). #CORTEX_API_NETWORK_RETRY_MS= # CORTEX_BUDGET_VISIBILITY / CORTEX_BUDGET_CONTINUE_MIN_REMAINING — R151 HB-BUDGET-VISIBILITY (4.108.21). The model was never told its # wall budget: on TB4.0's 8-hour tasks 45 of 49 fails ended in under 2 h (median 43 min), 43 of them with self-declared open items # ("did not get to execute it within budget" at 2 h of 8); the only time signal was the 90% WARN rung, which no failing session # reached. VISIBILITY (default on when CORTEX_TURN_DEADLINE_MS is set): a one-line WALL BUDGET total/elapsed/remaining reminder is # appended to the tool result each time elapsed crosses a 10% band (<=10 per turn; steering_injected kind budget_visibility). # CONTINUE_MIN_REMAINING (default 0.5; 0 = off): a finish whose draft lists open/unverified/unexecuted items while >= that fraction # of the budget remains gets ONE continue-with-budget nudge per turn (event budget_continue_nudge; rides the surrender-guard plumbing, # surrender takes precedence). Without a deadline both are silent (byte-identical to before). Same release: Bash doctrine edits — # no idle re-polling of background jobs, history-mining prohibition extended to filesystem grader hunts, and a new unprivileged- # verifier paragraph (never build at import; world-readable deliverables; re-run the checks as nobody) from vf2 59/60 + wal 94/97. # [LEDGER 2026-09-15 @4.108.21] BUILT + unit-tested (timeBudget.test.ts bands/line/levers; TurnEndGuards.test.ts open-items shapes). #CORTEX_BUDGET_VISIBILITY= #CORTEX_BUDGET_CONTINUE_MIN_REMAINING= # (no lever) R152 HB-EMPTY-COMPLETION-RETRY (4.108.22, 2026-09-15): during a 27-min DeepSeek incident (1:30-1:57 AM PT) chat/completions # returned bodies that parsed to null; the SDK handed them back, the translation layer dereferenced `.choices`, and the tool loop ended the turn # on the TypeError — 30 sessions across tb21-a21 A/B + tb4-flash-v3 (largest-eigenval died at iteration 1). R150's ladder did not apply (a null # body is a successful HTTP response). Now `completionBodyGuard.assertCompletionBody` throws EmptyCompletionBodyError (classified network) after # `chat.completions.create`, so CORTEX_API_NETWORK_RETRY_MS's ladder retries it; the translation layer is null-safe. # [LEDGER 2026-09-15 @4.108.22] BUILT + unit-tested (completionBodyGuard.test.ts incl. classifier hookup). # CORTEX_HERDR_REPORTING / CORTEX_HERDR_AGENT_NAME — R145 HB-HERDR-LIFECYCLE (4.108.14). Inside a herdr-managed pane (HERDR_ENV=1, HERDR_PANE_ID set, # `herdr` on PATH or HERDR_BIN) the orchestrator reports its lifecycle to herdr — `pane report-agent --source custom:nexus-cortex --agent # --state working|idle|blocked` at turn start/end and around approval waits, `pane report-metadata … --token summary=turn:|tool:| # waiting-approval` — fire-and-forget, deduped, 250 ms throttled, self-disables with one [WARN] on failure. Makes herdr's status AUTHORITATIVE # for nexus-cortex (sidebar rollups, `agent wait --until idle`). REPORTING=false disables; AGENT_NAME defaults to `cortex`. Companion R144: the # herdr agent skill is bundled at .cortex/skills/herdr (upstream skills/herdr/SKILL.md @ b99002ac, byte-identical to `herdr --skill` 0.9.0) and # gated by the new SkillTool `requires-env: HERDR_ENV=1` frontmatter — hidden outside herdr. # [LEDGER 2026-09-13 @4.108.14] BUILT + unit-tested (herdrReporter.test.ts, approvalWaitListener.test.ts, skill.test.ts env gating); NOT yet # exercised inside a live herdr server (none installed on the bench/repl beyond the CLI binary). Known gap: a THROWN turn leaves herdr at # `working` until the next turn re-syncs. # [LEDGER 2026-09-13 @4.108.15] SMOKE-VALIDATED LIVE on herdr 0.9.0 (session `bench` on the repl): after one turn `herdr agent list` shows agent # `cortex` idle with summary token turn:1; `agent wait --until idle` resolves on our report; target by PANE ID or a `rename`d live # name (the --agent label is the kind, not a name). Binary resolution order: CORTEX_HERDR_BIN (override) → HERDR_BIN_PATH (herdr's own pane # export) → PATH. # CORTEX_REASONING_EXHAUST_BACKOFF / CORTEX_REASONING_EXHAUST_BACKOFF_TURNS — R153 HB-REASONING-EXHAUSTION (4.109.0, 2026-09-16). The # tb4-flash-v3 sweep found 58 assistant turns in 23 of 63 sessions (a21h 8/7, a21l 4/4) that ended at EXACTLY 65536 output tokens with # 100-180K chars of reasoning, no text, no tool call — 3.8M output tokens burned — every one logged as reasoning_only_active and # nudged "take your next action", which re-ran the same derivation into the cap again; after 3 the turn ended (coq-block-bound: over at # iteration 10 with 97% of 8 h left). ROOT CAUSE: both tool loops passed the TURN'S FIRST stop reason to the empty-response classifier, # so the D-E `truncated` carve-out never saw a continuation's finish_reason=length (plus the streaming reassembly hardcoded stop/tool_calls). # FIX: lastStopReason is refreshed per response; streamed finish_reason survives; a truncated reasoning-only turn now (a) gets an # exhaustion nudge that says the budget was wasted and to act, and (b) arms BACKOFF: the next TURNS continuations (default 2) run one # reasoning-effort level lower (max/high → medium → low; repeat exhaustion steps down again); event kind reasoning_exhaustion # {iteration, outputTokens, from, level, turns}. Precedence: backoff > effort pulse > request param > card. 'false' keeps the nudge but not # the backoff. Streaming loop: the finish_reason=length break is now a warn (the truncation path handles it). # [LEDGER 2026-09-16 @4.109.0] BUILT + unit-tested (emptyResponseClassifier.test.ts R153 block). Field: PENDING (7-task R152/R153 patch cell). # [LEDGER 2026-09-16 @4.111.1] FIELD READ (tb4-p foodstuff-beta-activity, 4.111.0): classifier now says `truncated` and the backoff ARMED (high → # medium) — mechanism live. Defect: the empty-retry call consumed one lowered turn, so the second exhaustion (iteration 10) found the counter # empty and stepped high → medium again instead of medium → low. 4.111.1: the turn remembers the last stepped level (repeat = step down # from it) and the counter covers the retry call plus TURNS continuations. #CORTEX_REASONING_EXHAUST_BACKOFF= #CORTEX_REASONING_EXHAUST_BACKOFF_TURNS= # (no lever) R154 HB-IMAGE-REJECTION-HEAL (4.109.0, 2026-09-16): retro-console-soc generated a 128x128 8-bit GRAYSCALE PNG, called # ReadImage, and DeepSeek answered the next continuation with `400 .messages[290].image[0]: You have uploaded an unsupported image`; # the exception escaped after the tool batch, the already-executed guard left the loop, and the R29a synthesis failed on the same block — # session over at iteration 133 (43 min of 8 h). Now `orchestrator/imageRejectionHeal.ts` recognises the rejection (4xx + image wording), # stubs every user-side image block with a re-encode instruction, and the non-streaming continuation / empty-retry / R29a calls retry the # rebuilt request once (event image_rejection_heal {stripped, label, reason}). Streaming loop not healed (chunk-iteration surface). # [LEDGER 2026-09-16 @4.109.0] BUILT + unit-tested (imageRejectionHeal.test.ts). # (no lever) R155 HB-STATE-DIR-GIT-EXCLUDE (4.109.0, 2026-09-16): nextjs-performance committed a baseline with `git add -A` (sweeping # .cortex/sessions + artifacts into the commit) and a later `git checkout -- ...` restored a STALE session file over the live # one — the banked trajectory starts mid-session. When the state dir resolves to /.cortex and /.git exists, the runtime- # state paths (sessions/, artifacts/, training/, decisions.jsonl, memory/, projects/, .write-probe-*) are appended ONCE to .git/info/exclude # (marker line; worktree gitdir files followed; best-effort). CORTEX.md stays trackable. `git clean -x` is not covered by design. # [LEDGER 2026-09-16 @4.109.0] BUILT + unit-tested (stateDir.test.ts R155). # CORTEX_BASH_OOM_PRIORITY — R156 HB-OOM-CHILD-PRIORITY (4.109.0, 2026-09-16). mp-checkpoint-consolidation (tb4-flash-v3) and # extract-moves-from-video r3 (tb21-a21l) both died `Command failed (exit 137)` while a model-launched heavy process ran (three 600-s Bash # promotions in a row; a video decode): the OOM killer took the agent command including cortex-server — no response, no metrics row, # trajectory frozen. The Bash child shell now writes 1000 to /proc/self/oom_score_adj before the command (foreground and background # spawns; every descendant inherits it), so the kernel prefers the model's process over the orchestrator and the model sees "Killed" in the # tool result instead of the session vanishing. Linux only; best-effort; default on; 'false' = byte-identical command composition. # [LEDGER 2026-09-16 @4.109.0] BUILT + unit-tested (executors oomPriority.test.ts). Field: PENDING. #CORTEX_BASH_OOM_PRIORITY= # CORTEX_BUDGET_CONTINUE_MAX_NUDGES — R157 R151-v2 (4.109.0, 2026-09-16). Field audit of R151 on tb4-flash-v3: the budget line fired # in 63/63 sessions and the nudge 13 times, but detectOpenItemsText missed 36 of 52 failing finishes — 8 of them explicit surrenders # ("TASK NOT COMPLETE", "I did not prove", "did not fully solve", "honest status report", "fails the task's real success criterion", # "unable to") — and every nudged session finished on the very next turn (one-shot). OPEN_ITEMS_RES is broadened with those shapes # (tested against all 63 final messages: +8 catches, 2 pass-side false positives costing one nudge each) and the nudge re-arms up to # MAX_NUDGES per turn (default 2; 0 = off; max 10) with a firmer second text; event budget_continue_nudge carries {nudge, maxNudges}. # [LEDGER 2026-09-16 @4.109.0] BUILT + unit-tested (TurnEndGuards.test.ts R157, timeBudget.test.ts). Field: PENDING. #CORTEX_BUDGET_CONTINUE_MAX_NUDGES= # CORTEX_MENTOR_CONSULT_BUDGET_TOKENS — R158 HB-CONSULT-BUDGET (4.110.0, 2026-09-16). tb4-flash-v3 pretrain-shard-corruption: the # AskForAdvice mentor answer (mentor thinking off, 400-token content cap) came back finish_reason=length, 1721 chars, cut mid-sentence, # and the episode banked truncated:false (the flag was only set on the thinking-on empty-content path). Default hint cap 400 -> 800 # (clamp 100..4000); `truncated` now follows finish_reason=length on every helper call. # [LEDGER 2026-09-16 @4.110.0] BUILT + unit-tested (mentorRole.test.ts). Field: PENDING. #CORTEX_MENTOR_CONSULT_BUDGET_TOKENS= # CORTEX_ENDTURN_RESOLVER_MAX_REJECTS_BUDGETED — R160 HB-RESOLVER-BUDGET-CAP (4.111.0, 2026-09-16). Dig into the 27 confident-wrong # TB4.0 finishes (tb4-flash-v3): the EndTurn resolver was NOT the weak link — it saw the gap in 16 of the 22 sessions it judged (kv-live- # surgery "3.2x, not 5x"; rs-archive-clone "bad 3 of 288 — match the reference's decision boundary") and VETOED; the model came back # with the same attestation, the second GAP hit CORTEX_ENDTURN_RESOLVER_MAX_REJECTS=2 and the finish shipped as a fallback-accept a # median 24 min into an 8-h budget (median 3.5 min after the last veto). The liveness cap was sized for chat turns, not 8-h tasks. # Now the cap is BUDGET-AWARE: while >= CORTEX_BUDGET_CONTINUE_MIN_REMAINING (0.5) of the wall budget remains, up to MAX_REJECTS_BUDGETED # vetoes (default 6; clamp 0..20; 0 = liveness cap only); below that fraction or without a deadline, the liveness cap (2) as before. # From the second veto the fix plan carries an escalation line ("veto N of M, ~Xh left — close it or name the hard limit under # open_items"). Event endturn_resolver gains {cap, capLiveness, capBudgeted, remainingFrac}. Cost: false GAPs on passing work (4 of the # 9 judged passes ended on a GAP and still passed) now cost up to 4 more judge cycles — tokens, not correctness. A/B lever. # [LEDGER 2026-09-16 @4.111.0] BUILT + unit-tested (endTurnResolver.test.ts R160). Field: PENDING (first read on the next TB4.0 cell). #CORTEX_ENDTURN_RESOLVER_MAX_REJECTS_BUDGETED= # (no lever) R161 HB-JUDGE-TASKSHAPE (4.112.0, 2026-09-16): `isTaskShaped()` gated the EndTurn finish judge and the deadline-exit mentor # with a fixed coding-verb list — prompts like "Eliminate cumulative layout shift…", "To determine the beta activity…", "You are given … # LC-MS/MS data…" were NOT task-shaped, so 3 of the 7 patch-cell sessions (one a 353-turn finish that shipped broken) were never # adjudicated. Broadened verbs (eliminate/determine/identify/compute/solve/analyze/transcribe/report/produce/save/submit/…) + three # deliverable cues (an /app|/results|/output path; "save/write … as/to"; "N seconds to complete"). A bare question still reads false. # [LEDGER 2026-09-16 @4.112.0] BUILT + unit-tested (RequirementsVerification.test.ts R161). Field: PENDING. # (no lever) R162 HB-JUDGE-DELTA-BUILDDIRS (4.112.0, 2026-09-16): the judge's WORKSPACE DELTA capped the changed-file list at 60 BEFORE # skipping build/vendor dirs — sbt `target/` filled every slot on distributed-dedup and the edited SubmissionDedup.scala never reached the # judge (vetoes #1/#5: "source file NOT present in the WORKSPACE DELTA"). Skip dirs are now excluded in the scan itself (cap 400/200), # source-like files are listed first, and .cortex/.addon-tools/.ivy2/.sbt/.m2/.gradle/.npm join the skip set. # [LEDGER 2026-09-16 @4.112.0] BUILT + unit-tested (judgeEvidence.test.ts R162). Field: PENDING. # CORTEX_JUDGE_SEMANTIC / CORTEX_JUDGE_PROGRESS_MIN_CALLS / CORTEX_JUDGE_ESCALATE_REASONING — R165 HB-JUDGE-SEMANTIC (4.113.0, 2026-09-16, # operator: "stop hamstringing ourselves"). Three of the last four fixes were regex patches on SEMANTIC decisions (task-shape gate R161, # open-items phrases R151/R157, a fixed veto count R160) and each fit the last run's specimens. New split: deterministic code gathers # objective evidence and enforces limits; the judge decides everything semantic. SEMANTIC (default on): (1) every tool-using finish is # adjudicated (no task-shape regex gate; the deadline-exit mentor likewise); (2) the regex surrender/open-items nudges DEFER when the judge # adjudicated the finish (they remain the zero-cost path when the judge is off); (3) the judge emits `CONFIDENCE: high|medium|low` and # `CHECK: ` lines — the harness RUNS the named checks (bounded, up to 3) before the next adjudication and shows the results as ground # truth (the objective qualifier); (4) GAP is graded: low confidence with no failed check is accept-low-confidence, not a veto; (5) the veto # count is replaced by a PROGRESS condition — another veto needs >= PROGRESS_MIN_CALLS (3) tool calls since the last veto or a named check # now passing; a re-attest without progress gets ONE reasoning-on re-judge (ESCALATE_REASONING, per-surface CORTEX_ENDTURN_RESOLVER_REASONING # forced on for that call) and then accept-with-gap (event endturn_gap_accepted carries the plan + checks) — the R160 budgeted cap stays # as the ceiling. The judge prompt now carries PRIOR VETO ITEMS + harness-observed PROGRESS and must grade each prior item CLOSED/OPEN # first. Events: endturn_resolver gains {semantic, action, confidence, namedChecks, namedRan/Passed/Failed, callsSince, progressed, escalated}. # CORTEX_JUDGE_SEMANTIC=false restores the 4.111/4.112 gating byte-for-byte (the A/B control). # [LEDGER 2026-09-16 @4.113.0] BUILT + unit-tested (endTurnResolver.test.ts R165: parser, policy table, prompt). Field: PENDING (first read on the next cell). #CORTEX_JUDGE_SEMANTIC= #CORTEX_JUDGE_PROGRESS_MIN_CALLS= #CORTEX_JUDGE_ESCALATE_REASONING= # CORTEX_JUDGE_VETO / CORTEX_JUDGE_EVIDENCE_MAX_VETOES — R166 HB-JUDGE-EVIDENCE-VETO (4.114.0, 2026-09-17). Field read of R165 on the # TB4.0 38-task A/B (control = 4.111 gating, semantic = R165; both arms 4.113.0, 7 lanes, 3 vCPU/lane): the judge's FIRST verdict was GAP # on 18 of the 19 solutions the grader accepted (control 10/10, semantic 8/9) and it granted MEETS to 22 solutions the grader rejected # (9 control, 13 semantic); its own named checks FAILED on 6 passing solutions (one session: all three checks exit 1 with no output — the # checks were broken, not the work); 34 vetoes were issued while every named check passed; 33 of 76 sessions ran to the 6-veto cap, and # the R165 progress gate never fired (any passing check counted as progress — R166a fixes it to newly-passing checks). Outcome: control # 10/38, semantic 9/38, paired 5 vs 4 discordant — a wash bought at ~165 judge calls per arm. Opinion has no discriminative value, so # opinion no longer holds a finish. VETO=evidence (default): the harness runs the checks the verdict names IMMEDIATELY (up to 3); a GAP # holds the finish only when one of them FAILED, at most EVIDENCE_MAX_VETOES (1) times per session, and the junior sees the failing # command output in the HELD message; every other GAP is accept-with-gap (plan + checks on the endturn_gap_accepted event for # adjudication). VETO=opinion restores the R165 policy; VETO=never records only. Events: endturn_resolver gains {vetoMode, evidenceCap, # namedRanNow}. # [LEDGER 2026-09-17 @4.114.0] BUILT + unit-tested (endTurnResolver.test.ts R166 policy table). Field: PENDING (next TB4.0 cell). # R166b (4.114.1): a check is EVIDENCE only when it completed, exited non-zero AND printed output — a TIMED OUT check (45 s cap) or a # silent non-zero exit (the A/B's broken judge-authored commands: exit 1, no output, on a passing solution) is inconclusive and cannot # hold a finish. Event field namedInconclusive. #CORTEX_JUDGE_VETO= #CORTEX_JUDGE_EVIDENCE_MAX_VETOES= # CORTEX_TURN_CONTRACT — HB-TURN-CONTRACT (4.115.0, 2026-09-17; Terminus-2 disparity "suppress vs channel"). The boot-minimal door SUPPRESSES # deliberation ("Prefer acting over deliberating"; tuned at effort low). At effort high the model fought it: tb4-flash-v3 had 58 turns in # 23 sessions reason to the 65536 cap and emit nothing (R153). Terminus 2 CHANNELS deliberation: think freely, then every response must # carry analysis + plan + the action, and a length-truncated turn is re-issued at the SAME effort with an explicit "none of your actions # were performed, you exceeded N tokens, re-issue in smaller steps" message. =channel: the boot prompt drops the suppression clause and # appends the ANALYSIS/PLAN/action contract; the R153 exhaustion nudge becomes the Terminus message (cap named) and the effort backoff # defaults OFF (CORTEX_REASONING_EXHAUST_BACKOFF=true overrides). '' (default) = the shipped door, byte-identical. Probe 2026-09-17: # DeepSeek has NO hard reasoning budget (thinking.budget_tokens / max_reasoning_tokens ignored; reasoning_effort is the only soft lever; # reasoning counts inside max_tokens and starves the answer) — both harnesses hit the same wall; this lever changes the RECOVERY and the FRAME. # [LEDGER 2026-09-17 @4.115.0] BUILT + unit-tested (turnContract.test.ts). Field: PENDING (tb4 pilot-12, channel arm at effort max). #CORTEX_TURN_CONTRACT= # CORTEX_FINISH_CONFIRM / CORTEX_FINISH_CONFIRM_MIN_REMAINING / CORTEX_FINISH_CONFIRM_MAX — R167 HB-FINISH-CONFIRM (4.116.0, 2026-09-17, # pilot-12 hand-curation). The early-finish class is the whole game on the confident-wrong tail: 8/12 first finish attempts per arm # had >= 70% of the wall budget left (Terminus 2 too: 8/12 confident-wrong finishes in 15–105 min, its bare "are you sure" changed # nothing). Two grounded defects: (1) R165 deferred the budget-continue/surrender nudges whenever the judge adjudicated, INCLUDING # accept-with-gap — coq-block-bound surrendered honestly ("I did not complete the task", Admitted remains) at 73% budget left and # nothing pushed back; (2) the judge's accept-with-gap plans named REAL gaps (mvcc: `make repro` never run; hof: invalid CS; # rs-archive: malformed-input mismatches; coq: Admitted) that were recorded and never shown to the model. FIX: when the judge would # accept WITH a gap and >= MIN_REMAINING (0.3) of the budget remains, the finish is HELD once (MAX=1) with a zero-model-call # confirmation carrying the budget left, the reviewer's plan (advisory) and the junior's own open_items; the next EndTurn stands # unless an evidence veto (R166) applies. An accept-with-gap no longer silences the R151/R157 nudges (judgeOwnsFinish excludes it). # Event: finish_confirm {action, remainingFrac, confirms, planChars, openItems}. =false restores 4.115.0. # [LEDGER 2026-09-17 @4.116.0] BUILT + unit-tested (endTurnResolver.test.ts R167). Field: PENDING (pilot-12 rerun, confirm on vs off). #CORTEX_FINISH_CONFIRM= #CORTEX_FINISH_CONFIRM_MIN_REMAINING= #CORTEX_FINISH_CONFIRM_MAX= # CORTEX_MEETS_CONFIRM / CORTEX_MEETS_CONFIRM_MIN_REMAINING — R168 HB-MEETS-CONFIRM (4.117.0, 2026-09-17, pilot-12 rerun read). A MEETS was # unconditional: decideVetoAction accepted it on the verdict string alone, the judge's own CHECK: lines were never run for a MEETS, and # R167's hold excluded MEETS by construction — 2–3 sessions per arm finished on a WRONG MEETS at 81–92% budget left and walked straight # through (html-js-filter, mvcc-lsm-compaction, gsea). FIX: with the lever on the judge persona demands one to three `CHECK:` lines whose # PASSING proves the task's own criteria; the harness runs them at once; a MEETS with no passing evidence (nothing named, or every named # check failed/inconclusive, and the workspace's own check entry point did not pass) with >= MIN_REMAINING (0.5) of the budget left is # HELD once — sharing CORTEX_FINISH_CONFIRM_MAX with R167 — with the check results, the budget and the junior's open_items; an # unverified MEETS also no longer silences the R151/R157 nudges. A MEETS backed by a passing check stands. Event: finish_confirm # {action:'accept', meets:true, evidencePassed, checksNamed, namedRanNow, namedPassed, …}. =false restores 4.116.2 byte-for-byte. # [LEDGER 2026-09-17 @4.117.0] BUILT + unit-tested (endTurnResolver.test.ts R168). FIELD 09-17 (pilot-12 rerun-3 arm mc): DELIVERED, NULL, PRECISION-LIMITED — every MEETS named 2–3 checks, >=1 PASSED each time, hold fired 0x, 1/12 vs control 1/12 (ledger §9). #CORTEX_MEETS_CONFIRM= #CORTEX_MEETS_CONFIRM_MIN_REMAINING= # CORTEX_TURN_CONTRACT_ENFORCE / CORTEX_TURN_CONTRACT_ENFORCE_MAX — HB-TURN-CONTRACT-ENFORCE (4.117.0, 2026-09-17). The channel contract as # a PROMPT clause did not take (pilot-12: 6% of tool-calling turns carried ANALYSIS + PLAN; 8/10 sessions ignored it). Terminus 2 does # not ask — its parser REJECTS a response missing the fields and re-prompts. This is that structural half: with ENFORCE=true a # tool-calling response whose visible text lacks a line-leading ANALYSIS and PLAN is rejected — its tool calls come back UNEXECUTED as # error results carrying the re-prompt — up to ENFORCE_MAX (2) times per turn, then the batch runs as-is (liveness). Finish batches # (EndTurn) are exempt. Pair with CORTEX_TURN_CONTRACT=channel (the prompt half). Events: turn_contract_reject {iteration, rejects, # max, missing, tools}, turn_contract_fallback. Default off = byte-identical. # [LEDGER 2026-09-17 @4.117.0] BUILT + unit-tested (turnContractValidator.test.ts). FIELD 09-17 (rerun-3 arm tc): DELIVERED, NULL — 22 rejections / 10 fallbacks, compliance 6% → ~95%, 0/12 vs control 1/12, output +9% (ledger §9). #CORTEX_TURN_CONTRACT_ENFORCE= #CORTEX_TURN_CONTRACT_ENFORCE_MAX= # CORTEX_ACTION_PLAN_FIELDS — R172 HB-ACTION-PLAN-FIELDS (4.119.0, 2026-09-18, operator: "can we have the model output those as a structured # json requirement?"). Terminus 2's per-step shape is analysis + plan as FIELDS of the same JSON object as the commands. JSON mode # (response_format json_object) competes with native tool calling, so the faithful expression inside this harness is the action tool's # own JSON: with the lever on, Bash/Edit/Write schemas gain REQUIRED `analysis` + `plan` strings; a call missing either is returned # unexecuted with a corrective error EVERY time (no per-turn cap — unlike CORTEX_TURN_CONTRACT_ENFORCE, whose cap default 2 relented # in 10/12 pilot sessions; that clamp is raised to 10000 in 4.119.0 for a never-relent arm); valid calls have the fields stripped # before dispatch (executors + loop guards see bare params) and keep them in the canonical message, so every action's rationale is in # the trajectory. Event action_plan_reject {iteration, rejects, missing}. Cost: a few dozen output tokens per call. Default off. # [LEDGER 2026-09-18 @4.119.0] BUILT + unit-tested (turnContractValidator.test.ts R172). Field: PENDING (full-66 run arm vs control). # [LEDGER 2026-09-19 @4.119.1] FIELD, full TB4.0 (stack arm): 21 action_plan_reject events in 15/32 sampled sessions (enforced, model complied); outcome 12/62 vs control 12/62 — WASH. The Terminus "analysis+plan per action" half does not move flash here. #CORTEX_ACTION_PLAN_FIELDS= # CORTEX_JUDGE_TOOL_ROUNDS / CORTEX_JUDGE_TOOL_ROUND_BUDGET_MS — R170 HB-JUDGE-TOOL-LOOP (4.117.0, 2026-09-17). The v2 of # docs/LIFT_MENTOR_PLANNER_EXPERIMENT_SPEC.md §2.2/§2.4 ("bounded tool-using mentor, turn-capped never token-capped"), built as a # HARNESS-DRIVEN text protocol over the existing single-shot helper call: the helper request path carries no tools (no tools/ # tool_choice/tool role in any helper adapter), but the harness already RUNS judge-named checks (R166 runCheck) — the missing edge was # that the judge never saw the results of the commands it named in the same round. With ROUNDS > 1 the persona offers # `VERDICT: INVESTIGATE` + `CHECK: ` (read-only denylist: no rm/mv/git checkout/redirect-to-file/installs) + `READ: [:a-b]` # (in-workspace file slices, 120 lines / 4 KB, binary + oversize refused); the harness executes them, appends an EVIDENCE block and # asks again, withdrawing the option on the last round or when the aggregate ROUND_BUDGET_MS (240 s) or 2x that of the wall budget is # gone; an INVESTIGATE after withdrawal abstains (never re-loops). Investigation checks that pass count as evidence for R168. # The thinking-on escalation is skipped when >1 round ran. Event endturn_resolver gains {toolRounds, roundsUsed, investigateChecks, # investigateReads, investigateRefused, roundLatencyMs, evidenceChars}; `mentor` describes the LAST call. Default 1 = 4.116.2. # [LEDGER 2026-09-17 @4.117.0] BUILT + unit-tested (endTurnResolver.test.ts R170, judgeEvidence.test.ts R170). FIELD 09-17: 4.117.0 arm VOID (closing line overrode the offer; fixed 4.117.1); 4.117.2 arm jl2 DELIVERED + ENGAGED (5/26 adjudications multi-round, 27 checks/reads) — 2/12 vs control 1/12, within noise (ledger §9). # [LEDGER 2026-09-19 @4.119.1] FIELD, full TB4.0 (62 tasks, 1 repeat, in the STACK arm with resolver reasoning on @high + R172 + mentor high): 12/62 vs control 12/62 — WASH (7 flips each way, p 1.0). Engaged: 2–3 rounds in 59/87 adjudications, 122 checks + 183 reads. Lever pile CLOSED for TB4.0; ledger r-tb4-full-f1-2026-09-18.md. #CORTEX_JUDGE_TOOL_ROUNDS= #CORTEX_JUDGE_TOOL_ROUND_BUDGET_MS= # CORTEX_JUDGE_TOOL_AUTOLOOP — R170b (4.117.3, 2026-09-17, rerun-3 jl/jl2 field read). Offered INVESTIGATE (persona + closing # instruction, 4.117.2) the thinking-off flash judge NEVER took it: 0 investigations in the first 27+ adjudications at ROUNDS=3, while # it kept naming CHECK lines on its GAP/MEETS verdicts. The loop must not depend on the judge asking: with AUTOLOOP, a FIRST-round # verdict that names CHECK lines is treated as provisional — the harness runs them (read-only denylist), appends the EVIDENCE block # ("your provisional verdict was …; decide again on these results") and asks once more; checks run in the loop are cached so the # R166 evidence pass does not re-run them. Event endturn_resolver += {autoLooped, toolAutoLoop}. Needs ROUNDS >= 2. Default off. # [LEDGER 2026-09-17 @4.117.3] BUILT + unit-tested. FIELD 09-17 (arm jl3): ENGAGED HARD (9/25 adjudications multi-round, 56 checks/reads), NULL — 1/12 vs control 1/12; the judge re-issues the same verdict on its own checks' results (ledger §9). #CORTEX_JUDGE_TOOL_AUTOLOOP= # CORTEX_JUDGE_GAP_HOLD — R173 HB-GAP-HOLD (4.120.0, 2026-09-20; from the f1 curation r-tb4-f1-curation-2026-09-19.md: the judge often # named the real defect, the finish was accepted "with gap" because no harness-run check had FAILED (R166 evidence mode, effective veto # budget 1), and 96/100 failing sessions gave up with ~85% of the budget unused). With GAP_HOLD an evidence-mode GAP that names open # items is RETURNED to the junior — with or without a failed check — while >= CORTEX_BUDGET_CONTINUE_MIN_REMAINING of the wall budget # remains and the budgeted cap (MAX_REJECTS_BUDGETED, 6) allows; the R165 progress rules still apply (re-attest without progress → # one thinking-on escalation, then the finish stands). Below the floor, or with no deadline, R166 is unchanged. Event endturn_resolver # += {gapHold, gapHoldable}. Default off. # [LEDGER 2026-09-20 @4.120.0] BUILT + unit-tested (R173 block in endTurnResolver.test.ts). FIELD: pending (cell g1: control vs GAP_HOLD+SPEC_TESTS on the 29-task ever-passed cell ∪ the 13-task fixable pool). #CORTEX_JUDGE_GAP_HOLD= # CORTEX_JUDGE_GAP_HOLD_JEV / _MIN — R173b (4.120.0): typed gate on the hold via TypeSafe Jev (fixable_with_more_turns noul over the # task + the reviewer's items + the budget; ~0.3 s, $0.042/M input, zero output tokens; measured AUC 0.72 / ECE 0.06 on 262 sessions). # off (default) | shadow (bank jevFixable on the event, no control-flow change) | gate (hold only when P >= _MIN, default 0.3; fail-closed # to R166 when the call fails). Needs TYPESAFE_API_KEY in the executor env. The typed result changes control flow, never prose. # [LEDGER 2026-09-20 @4.120.0] BUILT + unit-tested (jevGate.test.ts). FIELD: shadow on cell g1 (bank the probabilities against the grader). #CORTEX_JUDGE_GAP_HOLD_JEV= #CORTEX_JUDGE_GAP_HOLD_JEV_MIN= # CORTEX_JUDGE_SPEC_TESTS / _MAX — R174 HB-SPEC-TESTS (4.120.0, 2026-09-20): BLIND spec-derived checks. At the first finish of a turn # a mentor call (endturn-resolver wire, its own persona) that sees ONLY the task text + environment report writes up to _MAX (4; 1..8) # read-only `CHECK:` commands that exit non-zero with a printed reason when a requirement the task states is unmet; the harness runs # them (R170 runner + denylist) at every adjudication, shows the results to the judge, and a FAILED spec check is objective evidence # for the veto (R166 checksFailed) — independent of the agent's own tests (83/100 failing sessions had their own test passing) and of # the judge's post-hoc checks (f1: 122 checks confirmed the agent's reading of the spec). Events: spec_tests {checks, genLatencyMs, # refused}; endturn_resolver += {specTests, specChecks, specRan, specPassed, specFailed, specInconclusive, specGenLatencyMs}. Default off. # [LEDGER 2026-09-20 @4.120.0] BUILT + unit-tested (R174 block in endTurnResolver.test.ts). FIELD: pending (cell g1). #CORTEX_JUDGE_SPEC_TESTS= #CORTEX_JUDGE_SPEC_TESTS_MAX= # CORTEX_JUDGE_VETO_MIN_REMAINING / _GAP_HOLD_MIN_INTERVAL_MS / _GAP_HOLD_PLAN_MAX_SIMILARITY — R173c (4.121.0, 2026-09-20, cell g1 # attribution r-tb4-g1-2026-09-20.md §3): the ONE attributable regression was an evidence veto at 15% budget (27 min left → fail; control's # judge accepted at 25% and passed); the three 6-hold failures re-finished six times inside 2–4% of the budget (the ≥3-call progress rule # passed while no work happened). Floor: below _MIN_REMAINING (0 = off; cell g2 arm: 0.25) no veto/hold of any kind — the gap is recorded # (event += belowFloor). Progress: a RE-hold needs ≥ _MIN_INTERVAL_MS (180000) since the last hold OR a plan whose token-Jaccard vs the # prior plan is < _PLAN_MAX_SIMILARITY (0.6); otherwise the R165 no-progress path (escalate once, then accept). Event += {holdProgressed, # msSinceLastHold}. The 4 pass flips (holds at ≥ 66% budget) are untouched by both. # [LEDGER 2026-09-20 @4.121.0] BUILT + unit-tested. FIELD: pending (cell g2). # [LEDGER 2026-09-21 @4.123.0] FIELD (cell g2, 28/35): floor WORKED — no veto below 25% in 28 sessions. Interval rule FAILED as OR: # production-planning held 6× at 45–137 s apart with holdProgressed=true every time (the judge rewrote its plan → similarity < 0.6). # R173c-b: the elapsed time is REQUIRED when known, the changed plan is additional; event += {holdGapMs, planSim}. FIELD: pending. # [LEDGER 2026-09-21 @4.124.1] g2 FINAL: g2x 8/35 vs control 9/35 (only-g2x 3 = protein/risk-scorer/vf2, all repeats of g1 flips; only-control 4, no lever # trigger). Two repeats of the lever config: 11 and 8 vs 9 → noise band. NOT a lift; keep dark. Ledger .cortex/bench/r-tb4-g2-2026-09-21.md. #CORTEX_JUDGE_VETO_MIN_REMAINING= #CORTEX_JUDGE_GAP_HOLD_MIN_INTERVAL_MS= #CORTEX_JUDGE_GAP_HOLD_PLAN_MAX_SIMILARITY= # CORTEX_JUDGE_SPEC_REPEAT_MAX / _SPEC_TESTS_AT — R174b (4.121.0): g1 read — 4 of the 8 passing lever sessions had a "failing" spec check # (false failures; protein-autointerp drove 6 holds on two wrong checks). A spec check that FAILS with the identical first output line at # _SPEC_REPEAT_MAX (2) consecutive adjudications while no OTHER check failed is `suspect`: shown to the judge with a caveat, not veto # evidence (event += specSuspect). _SPEC_TESTS_AT=lift authors the checks in the background at task lift (formal-crypto's first finish # came at 12% budget; at finish the checks arrived too late to matter); default finish = 4.120.0 behaviour. # [LEDGER 2026-09-20 @4.121.0] BUILT + unit-tested. FIELD: pending (cell g2). #CORTEX_JUDGE_SPEC_REPEAT_MAX= #CORTEX_JUDGE_SPEC_TESTS_AT= # CORTEX_JUDGE_INDEPENDENT_DERIVATION / _TOL — R176 HB-INDEPENDENT-DERIVATION (4.122.0, 2026-09-21; design docs/R176_INDEPENDENT_DERIVATION_DESIGN.md). # The largest never-passed TB4.0 class (~14 tasks: foodstuff, roy-polymorph, glycan, gsea, hof, vigenere, sound-change, cargo, ctr, # shadow-relay, satb, takens…) is a computed value / exact artifact graded against a golden answer with NO ground truth in the container: # the agent's own test passes, the judge sees a consistent story, holds return the same wrong value (g1: foodstuff held 6×). Lever: on a # value-shaped task (isValueShapedTask: names an output artifact + computation language), before a finish that would otherwise STAND, a # mentor call (endturn-resolver wire, DERIVATION_SYSTEM persona; sees task + deliverable + agent summary) names the agent's method and a # DIFFERENT method and emits CHECK lines that print `VALUE name=…`; the harness runs them (R170 runner) and reconciles (relative _TOL, # default 1e-3; strings by containment). Disagreement + genuinely different methods → the finish is held ONCE with both values shown. # Never below the budget floor. Events: independent_derivation {valueShaped, methods, checks, derived, agreement, compared, held}; # endturn_resolver += {derivation, derivationAgreement, derivationHeld}. Default off. # [LEDGER 2026-09-21 @4.122.0] BUILT + unit-tested (7 tests). FIELD: pending (value-shaped cell after g2). # [LEDGER 2026-09-21 @4.123.2] FIELD (cell r176, first 2 rows): FIRED but the evidence was invalid — heredoc CHECKs truncated to their first line, # every check failed, the fallback read a shell diagnostic as the value (false agree + false hold). R176b fixes parser/fallback; cell relaunched (r176b). # [LEDGER 2026-09-21 @4.124.4] FIELD (cell r176c, 4.123.3, 18 value-shaped tasks): 0/18; 8 disagreement holds all re-finished and failed; 2 agreements on # shared-wrong answers; 2 holds on controls that also failed in the control arm. Fires as designed, NO LIFT on the computed-answer class → keep dark. # [LEDGER 2026-09-21 @4.123.3] FIELD (cell r176b, first rows): heredoc checks now run whole and print real output, but the verdict marker sits # after the multi-line command text, so checksPassed read 0 → inconclusive everywhere. R176c locates the verdict by marker. Cell r176c relaunched. #CORTEX_JUDGE_INDEPENDENT_DERIVATION= #CORTEX_JUDGE_INDEPENDENT_DERIVATION_TOL= # CORTEX_FRAME / _CHOOSER / _CANDIDATES / _WAIT_CAP_S / _SCREEN_LINES — R179 HB-TERMINUS-FRAME + R178 typed chooser (4.124.0, 2026-09-21; design # docs/R179_TERMINUS_FRAME_PORT_DESIGN.md, docs/R178_TYPED_CHOOSER_DESIGN.md). The one variable never varied between our 18% and Terminus 2's 26.8 # on TB4.0 flash is the FRAME. `CORTEX_FRAME=terminus`: the model gets ONE tool, FrameAction (+ EndTurn), works one tmux pane; each turn returns # the screen (ANSI-stripped, last _SCREEN_LINES), a STATE card computed in code (turn, commands, last rc from a PROMPT_COMMAND hook, budget, # repeats, digest) and the harness templates (WAIT / INTERRUPT / SHOW MORE / RUN THE TASK'S TEST / RE-READ / FINISH). The prefix stays cached # (one small tool schema; the contract is appended to the system prompt on turn 0 and pinned); only the tool_result changes. `_CHOOSER=jev`: a typed # reader (Jev) sees the raw screen + state + the writer's candidates — never the judge (E0: it echoes it) — picks the action (>= 0.3), refuses # unsafe (>= 0.7), restricts repeats to templates, flags an unaddressed on-screen error (the writer then gets the full screen once); fail-open to # candidate 1. Every turn banks a `frame_turn` event (candidates, pick, probabilities, provenance, rc, wait) = Lens A rows on agent actions. # [LEDGER 2026-09-21 @4.124.0] BUILT + 23 unit tests (frames/); LOCAL SMOKE PASSED (deepseek-flash, toy task: 3 frame turns — orient, printf, cat/ls/wc — file correct, # EndTurn gate rejected once then accepted, 37 s, 3.5K tokens; frame_turn events banked with provenance); # [LEDGER 2026-09-21 @4.124.1] CHOOSER SMOKE PASSED locally (CORTEX_FRAME_CHOOSER=jev, k=3, toy CSV-sum task): 3 turns, Jev picked the writer's # 2nd candidate on turn 1 (0.86 vs 0.06), c1 on turn 2 (0.75), the FINISH template on turn 3 (0.73) → EndTurn; sum correct; ~340 ms per Jev call; # rows banked with provenance inserted/shown. FIELD: E1 (frame, chooser off) launched 11:54 AM PT 09-21 on g1-35; E2 (chooser on) next. # [LEDGER 2026-09-21 @4.124.2] E1/E2 FIELD (6+5 rows): sessions ran ~2x the control's wall time with FEWER turns — the runner's wait loop, not # the model (4–10 s/turn) nor Jev (0.6 s/turn): 25–44 turns per session waited 60–300 s. Fixed: exact requested wait (cap 60), 5-s grace while # the screen moves, STILL RUNNING hand-back; template list only when it changes. Smoke: `sleep 8` handed back at 5 s, model chose WAIT, 3–6 s/turn. # The 4.124.0/4.124.1 E1/E2 rows are a wait-loop measurement, not a frame measurement — cells relaunch on 4.124.2 (2 boxes per arm). E1 = frame vs control on g1-35 (~$40); E2 = chooser on (~$40). #CORTEX_FRAME= #CORTEX_FRAME_CHOOSER= #CORTEX_FRAME_CANDIDATES= #CORTEX_FRAME_WAIT_CAP_S= #CORTEX_FRAME_SCREEN_LINES= #CORTEX_FRAME_CONTRACT_EXTRA= # (no lever) R169 HB-NEARDUP-SCRATCH-STEM — REFUTED before shipping (2026-09-17, pilot-12 trajectory replay). The distiller's 16 # "repeated-identical-retry" candidates were re-read: the two stuck sessions (coq-block-bound base arm: `cat > /tmp/tN.v < tmux (TmuxManager) # > detached (R134). herdr backend: sibling pane via `pane split`, `pane run` + a __CORTEX_DONE____ sentinel awaited with `pane wait-output` # (R139/R142 inherited), >4 KB or multi-line input via `send-text` bracketed paste (R140 inherited), reads capped at 10 KB middle-omitted (R141), # BashOutput/KillShell handles for pane-hosted runs. Explicit herdr|tmux|detached forces a backend (unsatisfiable herdr → one [WARN], fall through). # [LEDGER 2026-09-13 @4.108.17] BUILT + unit-tested (TerminalBackend.test.ts 23, ShellToolHerdrBackend 4, TmuxSessionToolHerdr, CreateArtifactHerdrBackend) # + LIVE SMOKE on herdr 0.9.0 session `bench` (create/run rc=0/wait-output/timeout/heredoc paste/close all correct). Not yet in a bench run. #CORTEX_TERMINAL_BACKEND= # CORTEX_SUBAGENT_RUNTIME / CORTEX_HERDR_KEEP_DELEGATE_PANES — R147 HB-HERDR-DELEGATES (4.108.18). Task delegates can run as herdr agents in a # sibling pane instead of a forked IPC child: `pane split` under the parent's pane → `pane rename ` → `pane run` of the parent's own # cli agent-mode with --task-file/--result-file (prompt + env snapshot + controls ride a 0600 file the child unlinks; never argv) → wait loop # (`agent wait --until idle|done` slices + result file + exit sentinel) → transcript tail via `pane read` → the runner reports the pane's terminal # state (the child's own idle report is lost to the 250 ms coalesce at exit). Timeout = R133 limit + 15 s grace → C-c, status timeout with the # partial transcript. auto (default) = herdr only when HERDR_ENV=1, the herdr TerminalBackend resolves AND the parent auto-approves (herdr # delegates have no IPC approval channel); process = today's path; explicit herdr / Task `runtime:"herdr"` bypass the approval guard. # KEEP_DELEGATE_PANES default 1 (operator can inspect / `agent attach`); 0 closes the pane on completion. Rows: task_spawn.runtime[], delegate_pane. # [LEDGER 2026-09-13 @4.108.18] BUILT + unit-tested (HerdrSubAgentRunner.test.ts 13, delegateTaskFile.test.ts 7, AgentDispatchLifecycle 46) + LIVE # SMOKE on herdr 0.9.0 (delegate in w1:p8 returned DELEGATE-OK in 2.6 s, pane idle, summary delegate:completed). Not yet in a bench run. #CORTEX_SUBAGENT_RUNTIME= #CORTEX_HERDR_KEEP_DELEGATE_PANES= # Stage 4 (4.70.0, requires the gate ON): task-requirements attestation — # enumerate each stated requirement with what satisfies it + how it was # verified; mutating turns with no checks are challenged. Default OFF. # Values: false | true | strict. `strict` (4.90.0, item 10) adds two checks to Stage-4: # each `requirement` must be a VERBATIM clause of the task statement (paraphrase = lost # constraints) and each `verified_how` must quote the OUTPUT of a check executed THIS turn # (a claim with no matching tool output is rejected). Motivation: 4 pro fails # (cancel-async-tasks, dna-assembly, dna-insert, pytorch-model-cli) were 85-95% complete with # TRUE attestations verified against the model's own tests, not the task's exact constraints. # [LEDGER 2026-09-03 @4.91.0] DARK/PENDING → `strict` RECOMMENDED for k=5 with the gate. 4.91.0: verified_how also grounds on a Bash command that RAN this turn (12-char windows) so the recommended `$ cmd → output` form passes; Stage-1 reminder names `requirements`. v4 cell (n=1): strict rejects fired heavily (flash gate_req=22, pro=17), 0 control regressions. 🔴 4.90.0 strict CRASHED on EndTurn({}) (null.filter ×4, flash/dna-insert) and rejected 11 honest condensations as paraphrases (protein-assembly) → 4.90.1: null-guarded; verbatim = 24-char window OR ≥70% content tokens; nudge shows a pasted-output example. Needs GATE. # [LEDGER 2026-09-06 @4.93.0] ON=true (reson standard baseline — NOT strict). resolver-k5 ran REQUIREMENTS=true (verified in effective_config), not strict — that is the proven reson baseline; the earlier "strict recommended" is superseded by the actual reson config. Requires GATE=on. CORTEX_ENDTURN_REQUIREMENTS=true # CORTEX_ENDTURN_CITATION_LINEWISE — Stage-2 citation grounding matches multi-line quotes LINE-WISE (every non-trivial # line verbatim in the corpus; contiguity not required) and the corpus includes Bash-authored text + the task statement. # [LEDGER 2026-09-10 @4.100.0] ON (default true) — cell-d-k3 audit of 84 rejected citations: 47% real lines stitched from # several outputs (rejected as a block), 44% genuine fabrication (still rejected line-wise), 5% Bash-heredoc/task-statement # text (corpus gap), 2% normalization. Replay rescues ~60/84; 0 invented lines pass. =false restores whole-block matching. # Standing metric: endturn_rejections/session (k3 baseline 42/107 calls, 21/26 sessions). #CORTEX_ENDTURN_CITATION_LINEWISE=true # ============================================ # DECISION STORE (prior-recall + recording) # ============================================ # Append each tool decision to /.cortex/decisions.jsonl (default ON) CORTEX_RECORD_DECISIONS=true # Inject prior decisions as a before tool use (default ON) CORTEX_LOOKUP_PRIOR_DECISIONS=true # decisions.jsonl self-rotates at this byte cap (default 2 MB) CORTEX_DECISIONS_MAX_BYTES=2097152 # Per-turn "Repository State" harness-note: git branch, uncommitted changes in the project # subtree, recent commits, and a cross-agent staleness warning (files you read that another # agent/the user has since changed on disk). Lets two agents share one working tree safely. # Default ON; set "false" to disable. # [LEDGER 2026-09-12 @4.108.4] The bench COMMON pins this false (per-turn prompt mass under the narrow door); the note already no-ops outside a # git repo (rev-parse fails → null), so repo-ness was never the cost — cadence was. 4.108.4 builds it ONCE, forced past this lever, inside the # compaction reminder (WORKSPACE STATE), with the mtime file delta as the non-repo fallback: the model's own edit history, replaced from disk # right after it was dropped. Keep the per-turn lever as it is; the one-shot rides on CORTEX_COMPACTION_RESUME. CORTEX_GIT_CONTEXT=true # Turn-0 "Available Slash Commands" harness-note: lists the built-in /commands (grouped by category) # so the model can SUGGEST them to a user when relevant. Interactive/workspace feature — there is no # user in a headless/bench task, so it is pointless prompt mass there. Default ON; set "false" to drop # it (the bench COMMON sets it false). [LEDGER 2026-09-09] added — headless/bench frame hygiene. CORTEX_SLASH_COMMAND_HINT=true # ============================================ # ORCHESTRATOR MODE # ============================================ # Orchestrator lifecycle: persistent (default) | stateless (clean per request) | server CORTEX_MODE=persistent # Server URL when CORTEX_MODE=server (HTTP client mode) CORTEX_SERVER_URL=http://localhost:4000 # ============================================ # AGENT WORKSPACE # ============================================ # tmux visual monitoring for parallel agent teams (one live pane per agent) AGENT_TMUX_MONITOR=false # ============================================ # TESTING # ============================================ # Run real-API smoke tests instead of mocked ones ENABLE_SMOKE_TESTS=false # Run the Chromium browser-integration test suite (drives a real browser, # downloads http-server via npx — opt-in; default npm test skips it) ENABLE_BROWSER_TESTS=false # ============================================ # DEBUG FLAGS # ============================================ # Log raw API request/response payloads DEBUG_PAYLOAD=false # Verbose system-message assembly logging (also enabled by DEBUG=true) DEBUG_SYSTEM_MESSAGES=false # Show thinking/reasoning content in the CLI. For Anthropic Opus 4.7/4.8 (adaptive # thinking) 'true' requests display:'summarized', which BILLS extra output tokens # ($25/1M on Opus 4.8); 'false' keeps reasoning omitted (empty thinking blocks, $0). # Other providers (XAI/DeepSeek/GPT) stream reasoning for free regardless. DEBUG_THINKING=false # ============================================ # TOOL & PATH OVERRIDES # ============================================ # Override the Chromium binary used by web/browse tools (auto-detected if unset) CHROMIUM_BIN= # Alternate Chromium path honored by Playwright PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH= # Override the tmux binary used by visual agent monitoring (auto-detected if unset) # [LEDGER 2026-09-13 @4.108.8] R134 HB-TMUX-FALLBACK: when tmux is ABSENT, Bash `persistentSession` and CreateArtifactTool persistent/dev # process artifacts no longer refuse — they degrade to a detached background process (BackgroundProcessRegistry; poll with BashOutput) with a # `[WARN] tmux not available: ...` first line naming the lost semantics (state/cwd/env persistence, attach/reconnect, dashboard restart). # Field read: TB4.0 ctr-optimization (no tmux in the image) lost its long-running monitor after 16 refused CreateArtifactTool calls. # [LEDGER 2026-09-13 @4.108.18] R140 HB-TMUX-PASTE-BUFFER (Terminus 2 tmux_session.py:661-687): TmuxManager.sendKeys routes multi-line or >2000-byte # input through a 0600 temp file + `tmux load-buffer` / `paste-buffer -d -p` (bracketed), Enter always a separate send-keys; short input stays # `send-keys -l`. Fixes heredoc/`python3 -c` bodies breaking at the send-keys limit (TB4.0 rs-archive-clone "unexpected end of file"). Smoke: # 8733-byte heredoc byte-exact through tmux; 6 KB via herdr send-text. # CORTEX_TMUX_AUTO_INSTALL / CORTEX_TMUX_STATIC_URL / CORTEX_TMUX_HISTORY_LIMIT / CORTEX_TMUX_PANE_SIZE — R138/R139/R141 (4.108.19), from Terminus 2's # tmux_session.py. R138: when tmux is missing and AUTO_INSTALL != false, the first persistent-mode request tries (time-bounded 120 s each) the # detected package manager (apt-get with expired-Release tolerance, apk, dnf, yum, brew) then a static binary from STATIC_URL into ~/.local/bin # (no default URL = skipped), then degrades (R134); one [INFO]/[WARN]; cached per process; runs as the harness user (no sudo). R139: blocking # persistent runs signal completion with `tmux wait-for -S ` and block on the channel under a hard in-process cap (cap expiry = timedOut, # process left running) — the 400 ms sentinel poll remains only for `wait_for` regex waits. R141: sessions are created with history-limit # (default 50000) and a fixed pane (default 160x40); every tmux capture/read is capped at 10 KB middle-omitted; TmuxSession capture gains `lines`. # [LEDGER 2026-09-13 @4.108.19] BUILT + unit-tested (TmuxManager 19, TerminalBackend 33, TmuxSessionToolCaptureCap 4, ShellTool 63) + tmux SMOKE # (create 50000/160x40; wait-for rc; cap expiry timedOut with the process alive; 40 KB capture → 10 KB). Smoke caught + fixed: the tmux client # traps SIGTERM and exits 0, which execFile's timeout reported as success — the exec now owns the timer (SIGKILL + explicit killed). #CORTEX_TMUX_AUTO_INSTALL= #CORTEX_TMUX_STATIC_URL= #CORTEX_TMUX_HISTORY_LIMIT= #CORTEX_TMUX_PANE_SIZE= TMUX_BIN= # Google Vertex AI project (only when using Vertex instead of the Gemini API) GOOGLE_CLOUD_PROJECT= # Extra directories to grant tool access to, OUTSIDE the project root (the --add-dir # mechanism — your explicit permission). Path-delimiter separated (':' on Linux/macOS). # Example: /data/shared:/opt/reference. Prefer the --add-dir flag for one-offs. CORTEX_ADD_DIRS= # ============================================ # GIT / PR ACCESS CONTROL # ============================================ # Controls the git/PR tools (PRAgent, WorkspaceManager) and the /v1/pr/* server routes. # Input-format validation (which blocks shell/argument injection) is ALWAYS on; the # allow-lists below are opt-in defense-in-depth. # # Comma list of repos the tools may touch: exact "owner/repo", "owner/*", or "*". # Unset = ALL repos are permitted — the convenient default for single-user/local use. # For shared or multi-tenant deployments, RESTRICT this to the repos you trust the tools # with, e.g. GIT_ALLOWED_REPOS=me/app,me/* GIT_ALLOWED_REPOS= # Comma list of allowed actions: review,list,create,post-review,clone,worktree,diff,cleanup,status # Unset or * = all actions allowed. GIT_ALLOWED_ACTIONS= # Token for gh/git. Injected into the subprocess env as GH_TOKEN/GITHUB_TOKEN only — # never placed on argv or in a clone URL. Leave unset to use gh's own auth. GIT_AUTH_TOKEN= # GitHub (Enterprise) host for git/PR tools. Default: github.com GIT_HOST=github.com # HMAC secret for the /v1/pr/webhook endpoint (GitHub X-Hub-Signature-256). # Unset = the webhook is DISABLED (returns 401) rather than accepting unsigned calls. GITHUB_WEBHOOK_SECRET= # ============================================ # SERVER LIFECYCLE (startup / shutdown / resume) # ============================================ # HTTP server port (falls back to the next free port if taken) PORT=4000 # Startup resume: load the most recent session on boot — e.g. after an idle-shutdown -> # wake cycle. For a specific session set RESUME_SESSION_ID instead. Default: fresh session. AUTO_RESUME=false # Resume a specific session UUID on boot (overrides AUTO_RESUME) RESUME_SESSION_ID= # Inactivity shutdown: auto-stop after N seconds with no requests. # 0 = never (always-on daemon) # N>0 = stop after N seconds idle. Pair with a process manager (systemd, pm2) + # AUTO_RESUME=true for "sleep when idle, resume on wake" — cost-efficient # on-demand use without losing conversation state. SERVER_IDLE_TIMEOUT=0 # Graceful shutdown: max ms to let in-flight connections drain before forcing exit # (0 = wait indefinitely). On shutdown the dashboard view server, idle timer, and # cleanup intervals are all closed cleanly first. SHUTDOWN_GRACE_MS=10000 # Opt-in: start the sandbox+tmux dashboard (default off; binds an extra port). # MASTER SWITCH for the tmux/sandbox web dashboard (the 4001 view server). # false = the dashboard NEVER starts (not at boot, not on TmuxSession/CreateArtifact # use) and tools return guidance instead of view URLs. Set true to enable; if it # fails to start, check for a port conflict on DASHBOARD_PORT (retries 10 ports). ENABLE_DASHBOARD=false # Dashboard port — honored whether started eagerly (above) or lazily by a tool DASHBOARD_PORT=4001 # ============================================ # RUNTIME FLAGS # ============================================ # Auto-approve ALL tool executions (bypasses the permission system). Use with caution. YOLO=false # Proactive mentorship discovery (runtime flag) MENTORSHIP_ACTIVE_DISCOVERY=false # ============================================ # SYSTEM PROMPT DELIVERY + COMPOSITION (R63/P6, 2026-08-18) # ============================================ # R63 delivery: static system prompt on chat/completions + Responses paths. # DEFAULT ON since 4.66.0 (P6e/P6f/P6g testing complete). The deepseek cards' # boot-minimal promptPreset keeps that family cheaper than the promptless era. # Set to false to opt out (restores the pre-R63 promptless behavior). #CORTEX_DELIVER_SYSTEM_PROMPT=false # Prompt-mass composition (BASH_PLUS_SPEC P6): full (default) | minimal (only # the core system prompt; guides/CLAUDE.md/memory dropped) | defer (minimal on # turn 1, full corpus appended once at the first tool-result boundary). # defer COMPOSES with a card's promptPreset (item 9a): a boot-minimal card # keeps its narrow replacement prompt on turn 1 and receives the full corpus # (incl. project CORTEX.md/AGENTS.md, read lazily at lift) after first action. # Effective on providers only where delivery is ON (see flag above). #CORTEX_PROMPT_MASS=minimal # Replace the core SYSTEM_PROMPT.md with a file (e.g. the measured presets in # docs/prompts/: boot-prompt.md = P6c winner, orient-prompt.md = runner-up). #CORTEX_SYSTEM_PROMPT_FILE=./docs/prompts/boot-prompt.md # ============================================ # FIRST-TURN TOOL ANCHORING (BASH_PLUS_SPEC P0/P1) # ============================================ # Env override for the model card's anchorProfile (deepseek cards default to # bash-edit). Values: lean | bash-only | bash-plus | bash-edit | none. # [LEDGER 2026-09-02 @4.89.0] ON=bash-edit — the P6/dsh narrow door (turn-1 action forcing). Set explicitly so the A1 bench arm is unambiguous; card applies it anyway. CORTEX_TOOL_ANCHOR=bash-edit # ── Vision / image-path bridge (item 7) ── # Turns an image stays in the request context before being stubbed out. # MEASURED: an image ANYWHERE in a vision-exp request disables cache reads for # the whole request — evicting after use restores the ~31x cache discount. # 'off' keeps images forever. #CORTEX_IMAGE_TTL_TURNS=3 # ReadImage downscales originals above this size to ~800px (provider parity, # lossless to the model, ~100x wire cut). 'off' disables. #CORTEX_IMAGE_DOWNSCALE_BYTES=2097152 # Anchor FRAME (4.70.0): true/persist = the anchored tool surface never lifts # (stays the only surface all session); false/lifted forces the lift. Unset = # the model card's frameProfile, default lifted. Experiment lever. # [LEDGER 2026-09-02 @4.89.0] DARK by design — held frame helps flash on hard tasks (ARS flip) but induces PARALYSIS on pro (never_acted 0→5); belongs on the model CARD per tier, not global. #CORTEX_TOOL_ANCHOR_PERSIST=false # RL-entry cue line prepended as the first system line (refuted in P1 — do not # ship; kept as an experiment lever). #CORTEX_ANCHOR_CUE= # Session-wide tool profile (independent of first-turn anchoring). # [LEDGER 2026-09-02 @4.89.0] DARK/experiment arm — liftmin (bash-plus) LOST to lifted control; keep unset (=full). #CORTEX_TOOL_PROFILE=full # Dedicated-tool steering in ShellTool (redirects bare `cat FILE`/`sed -i`/ # literal `echo > f`/bare `grep` to Read/Edit/Write/Grep with a guidance # error). 'off' disables ALL such redirects — for bash-focused models # (narrow-door program: modern + trained small models handle shell idioms # natively and work best when bash is not second-guessed). Default: on. #CORTEX_TOOL_REDIRECTS=on # ============================================ # CANON STORE (cross-harness session rail) # ============================================ #CANON_REPO= #CANON_STORE= #CANON_AUTO_SYNC=false # SCOPED sync (sync-only stores, e.g. containers capturing their own sessions): # 'auto' = materialize only the legs whose harness roots exist on THIS machine; # or an explicit comma list of harness labels. Unset = full surface (repl # default — translate/graph need everything and REFUSE scoped stores). #CANON_SYNC_SCOPE= # Force a FULL (non-partial) store clone — auto-clones default to # --filter=blob:none (history metadata only; ~halves a multi-GB store). #CANON_FULL_CLONE=false # `canon archive` age threshold: sessions whose last commit is older than this # many days move to archive/YYYY-MM (remote keeps all; local worktree stays flat). #CANON_ARCHIVE_DAYS=30 #CANON_AUTO_SYNC_DEBOUNCE_MS=30000 # ============================================ # MISC # ============================================ #CORTEX_UPDATE_POLICY=notify # ============================================ # RUNTIME / CONNECTIVITY (documented by the R65 env-docs check) # ============================================ # Route ALL provider calls through a proxy base (hosted-container mode). #CORTEX_PROXY_BASE_URL= # Server the CLI talks to (defaults to http://localhost:4000). #CORTEX_URL= # Explicit path to the server entry for auto-start. #CORTEX_SERVER_PATH= # Project root override for autoresearch/backlog tooling. #CORTEX_ROOT= # Verbose harness debug logging (coarser than DEBUG). #CORTEX_DEBUG=false # Auto-approve tool permissions in headless runs (YOLO-equivalent; use with care). #CORTEX_HEADLESS_APPROVE=false # Auto-connect configured MCP servers at session start. #CORTEX_MCP_AUTOCONNECT=false # Sub-agent sampling temperature override. #CORTEX_SUBAGENT_TEMPERATURE= # Fetch timeouts (ms) for bench runners / client HTTP. #CORTEX_BENCH_FETCH_TIMEOUT_MS= # Client-side ceiling on ONE /v1/messages round-trip (CLI one-shot, CortexClient, OrchestratorClient; # code default 900000). Durable-worker invariant 7: every cap sits ABOVE the largest legitimate unit # of work so the task's own budget governs, never a plumbing timeout. # [LEDGER 2026-09-02 @4.90.0] ON=12600000 (was 3600000) — p3 timeout audit: 3600s was a LATENT SELF-CUT on TB2.1's 3600/7200/12000s-budget tasks (Harbor max 12000s + build); bench adapter v21 pins 12600000 (curl -m matches). Raised here so a fresh install cannot self-cut a long headless task. CORTEX_CLIENT_FETCH_TIMEOUT_MS=12600000 # P0 compliance gate: allows sk-ant-oat01 subscription tokens on the raw # Messages path ONLY with Anthropic program approval. Leave unset otherwise. #CORTEX_SUBSCRIPTION_AUTH_APPROVED=false # Canon: redirect canon CLI log output to a file. #CANON_LOG_FILE= # Bench-runner stamps (usually set per-invocation by cortex autoresearch bench, # not in .env): holdout-split marker, benchmark source label, experiment tag. #CORTEX_BENCH_HOLDOUT=false #CORTEX_BENCH_SOURCE=cortex-bench #CORTEX_EXPERIMENT_TAG= # Item 10 — helper-curated doctrine freshness (session-start / defer-lift boundary). # When true, a staged mechanical CORTEX.md refresh (written by the orient script on # drift) is curated by the HELPER model in a side context and applied atomically # (with .prev rollback) BEFORE doctrine is delivered — synchronous, bounded, # fail-open to the previous doc on timeout. The MAIN model never sees the diff. #CORTEX_DOCTRINE_CURATION=true # Curation wait bound (ms) and output size budget (bytes). #CORTEX_DOCTRINE_CURATION_TIMEOUT_MS=25000 #CORTEX_DOCTRINE_MAX_BYTES=16384 # Item 12 — task-integrity guard (anti-reward-hacking; TB2.1 bench + serving profiles). # Appends one static line to the system prompt (survives boot-minimal, prefix-stable): # outputs must derive from executed work — never retrieved/recited solutions. # [LEDGER 2026-09-02 @4.89.0] ON — guard stack (anti-reward-hack line, survives boot-minimal). tb21g +11 engaged net. CORTEX_TASK_INTEGRITY=true # Poll guard (busy-wait class): one nudge after N consecutive identical SUCCEEDING # calls (run3 deficiency finding). Default off; arm in bench/serving profiles. # [LEDGER 2026-09-02 @4.89.0] ON — guard stack (busy-wait nudge @4 identical succeeding calls). tb21g +11 engaged net; doctrine-mine busy-wait class. CORTEX_POLL_GUARD=true #POLL_REMIND_AT=4 # EndTurn Stage-5 integrity verifier (item 12 layer 4): mechanical checks at the # gate — web-content transplant + solution-shaped queries (AUDIT-ONLY events when # a sources attestation is present: justify-don't-block) + mandatory show-your-work # `sources` attestation whenever web tools were used this turn (the one rejecting # check; bounded nudges, fallback-accept). # [LEDGER 2026-09-03 @4.91.0] ON — guard stack Stage-5 (transplant/solution-query audit + sources attestation; justify-don't-block); since 4.91.0 also evaluated on the streaming path. Constant-on in every bench arm incl. controls. Fired 'unattested web use 12/12' on protein-assembly (fd) → one of 3 web-tool taxes behind ENABLE_WEBTOOLS. CORTEX_ENDTURN_INTEGRITY=true # Item 13b — surrender guard: one "execute your plan" nudge when a tool-using turn # ends by ENUMERATING remaining steps instead of doing them (the honest-premature- # surrender class). Default off; bench/serving profiles arm it. # [LEDGER 2026-09-02 @4.89.0] ON — guard stack (execute-your-plan nudge on remaining-steps finishes). tb21g +11 engaged net. CORTEX_SURRENDER_NUDGE=true # Item 14b — windowed near-dup breaker: outcome-agnostic sliding-window counter over # the normalized approach hash (catches varied-param polling invisible to the exact # tracker AND the poll guard — observed x65 near-identical calls, max 4 consecutive). # N-in-window → one diversify nudge; 2N → break. Default off; bench/serving arm it. # [LEDGER 2026-09-02 @4.89.0] ON — guard stack; the retry-loop ladder (retry_loop = 65-74% of fails pre-guards). Code defaults NEARDUP_NUDGE_AT=12 (8 regressed rstan-class grinds) / NEARDUP_WINDOW=30 (break rung unreachable at 20). # [LEDGER 2026-09-13 @4.108.9] R128 HB-CHUNKED-READS: the near-dup lens, the loop ladder's approachHash/poll guard and the slice_read nudge/block # now recognize a RANGE PROGRESSION over one file (sed -n 'A,Bp' / head|tail / tail -n +A|head / awk NR / Read offset+limit with next.start > # prev.end) as new work, not a retry; an identical, overlapping or backwards range still counts. Field read (tb4-flash-v1): 25 of 92 loop-guard # events fired right after a chunk read (rs-archive-clone 5). Tests: chunkReadProgression.test.ts, LoopLadder.test.ts, sliceBlock.test.ts. # [LEDGER 2026-09-13 @4.108.12] R136 HB-NEARDUP-SCRIPT-SHAPE: DIFFERENT experiment scripts under one shell wrapper (`cd … && timeout N python3 -u # /tmp/{search,unfused,moe_search,grad_diag}.py 2>&1 | grep -vE …`) scored as near-duplicates → 3 neardup-similarity tool blocks → Bash disabled → # a task the previous build PASSED was abandoned (TB4.0 validation mp-checkpoint-consolidation). Now: command IDENTITY (executed script paths; # inline `-c`/heredoc bodies compared by body Dice) gates the similarity lens BEFORE the wrapper-shape compare, and (R136b) the script-path # digest suffixes the approach key for the hash lens + failure ladder (R128's pattern). Same script with tweaked flags / minor-edit inline # grinds still count; commands without identity (ls/grep/git) unchanged. Tests: commandIdentity.test.ts, LoopLadder.test.ts R136 block. # [LEDGER 2026-09-13 @4.108.13] R135 HB-POLL-LOOP: a legitimate POLL-AND-WAIT (`sleep 115; curl -s …/config | python3 -c …` on a 48-sim-hour # task) was scored as a stuck approach → 3 neardup-similarity tool blocks removed Bash → the model routed around via CreateArtifactTool and # finalized without observing its eval window (TB4.0 ctr-optimization). Now: detectPollPattern (wait + read-only probe, no write verbs) — # an ok poll feeds NEITHER lens NOR the failure ladder and instead returns `poll_steer` at the 3rd consecutive same-probe poll (then every # 10th): "move the wait off the turn: run_in_background / persistentSession + BashOutput; foreground waits <= 60 s". loop_tool_block never arms # on a poll and (last-executor guard) never removes the only execution tool — it downgrades to the reminder (`loop_block_downgraded`). # R135b: byte-identical Bash polls count toward MAX_LOOP_REPETITIONS only when the RESULT is also identical (R137's rule). Failing polls still # climb the ladder (soft exit) but are never hard-blocked. Tests: pollPattern.test.ts, LoopLadder.test.ts R135/R135b, loopToolBlock.test.ts. CORTEX_NEARDUP_BREAKER=true # Slice-reader nudge: after the 3rd bash slice-read (sed -n N,Mp / head -n / tail -n) of the SAME file in a session, # append a one-line reminder to read the file once with Read (offset/limit) instead. Event kind: slice_read. # [LEDGER 2026-09-03 @4.91.0] ON — ✅ v5 CERTIFIED: slice_read fired (flash 3 / pro 4, on gcode/make-doom/train-fasttext/dna). Doctrine gap flagged 08-29 (A′ doctrine-mine) and recurring in v4 make-doom on BOTH models (5 sed slices of /app/vm.js each); the Bash description's Read-preference line alone does not hold under the bash-edit frame. Post-tool reminder = no turn-1 prompt mass. CORTEX_SLICE_NUDGE=true # HB-SLICE-BLOCK — coercive escalation of the slice-nudge (dark). Full-sample mining (k5 @4.91.1, 66 nudge-fires) # proved the soft slice-nudge is IGNORED ~80% of re-tested cases (93% of ignored files are NEVER Read); harm # concentrates in a 39% deep-grinder tail (up to 23 extra slices of one file). So after CORTEX_SLICE_BLOCK_AT # slices of a STATIC/source file, BLOCK further slice-reads of it (force Read via an append-only redirect, # cache-safe), bounded to CORTEX_SLICE_BLOCK_MAX/file; append-mostly logs (re-tailing) are EXEMPT. Banks slice_block. # [LEDGER 2026-09-09 @unreleased] DARK/PENDING — built + 11 unit tests green; A/B on the slice-heavy source pop # (gcode/make-doom/dna-*/fix-ocaml-gc/build-pmars/make-mips) owed. Spec: docs/HB-SLICE-BLOCK-SPEC.md. # [LEDGER 2026-09-10 @4.101.0] ON (default true) — cell-d-k3: the soft nudge fired 23× on 17/42 rows and was IGNORED (61 more # bash slices vs 5 Reads after it; 3 files switched, 15 kept slicing). The block is the escalation the nudge was designed # to hand off to; append-log exemption + MAX=2/file bound the false-positive risk. =false → nudge only. #CORTEX_SLICE_BLOCK=true #CORTEX_SLICE_BLOCK_AT=5 #CORTEX_SLICE_BLOCK_MAX=2 # Orient bootstrap directive: when a bare box lacks the language/compiler/library the task needs, orient prints one # principled "install what you need + install once + fast cached installer" line. GATED because it is UNPROVEN — # the one bare-box pass we have (tp torch-tensor, 4.91.0) happened with ONLY orient's factual tooling line, no # directive. The factual tooling line is always on; this flag adds the directive. # [LEDGER 2026-09-03 @4.91.1] DARK (default 0) — ships dark, A/B-able (def-60a1dfc55a); do NOT bake into the k=5 pin. # [LEDGER 2026-09-06 @4.93.0] ON=1 (reson standard, operator directive: match the full bench COMMON). CAVEAT: was a SHARED BASELINE in both k5 arms (on in reson AND resoff), so NOT independently A/B-validated — it's part of the proven reson BUNDLE (+17pp) but its solo contribution is unmeasured. A/B-able (def-60a1dfc55a) if isolated efficacy is ever needed. CORTEX_ORIENT_BOOTSTRAP=1 # [LEDGER 2026-09-02 @4.89.0] code default 30 (4.88.0) — 20 made the break rung (2N=24) unreachable; preserves 40%/80% density semantics. #NEARDUP_WINDOW=30 # [LEDGER 2026-09-02 @4.89.0] code default 12 (4.88.0) — 8 misfired on persistence-wins grinds (rstan-to-pystan regressed both arms). #NEARDUP_NUDGE_AT=12 # NEARDUP_SIM_AT / NEARDUP_SIM — HB-LOOP-NEARDUP (2026-09-10): a SIMILARITY near-dup lens for EXECUTING tools # (Bash/Write/Edit; slice-reads excluded): bigram-Dice ≥ NEARDUP_SIM over the last NEARDUP_WINDOW executing calls; # diversify at NEARDUP_SIM_AT, break at 2×. This is what arms CORTEX_LOOP_TOOL_BLOCK on real loops. # [LEDGER 2026-09-10 @4.101.0] ON with the breaker — replay of 47 real sessions (cell-l loops + cell-d-k3): the hash # lens peaked at 7-in-30 on every genuine loop (12 unreachable; top hits were paging Reads) → cell-l fired 0×. Similarity # ≥0.9 on executing tools: every real loop crossed 7 (dna-assembly 7/7, gcode python -c 18); no PASSING session did # (max 6). Also fixes the masking bug (a failure-ladder remind hid a near-dup diversify). #NEARDUP_SIM_AT=7 #NEARDUP_SIM=0.9 # CORTEX_LOOP_TOOL_BLOCK — hard loop intervention (operator design 2026-09-07). On a ladder-detected # non-converging loop (diversify/break), disables the LOOPING TOOL'S EXECUTOR for one turn (cache-safe: # the tool stays in the list, so the prompt cache is NOT busted) and returns an append-only redirect # error steering to the complementary tools (Bash→Read/Write/Edit, Edit→Read/Bash). After 2 blocks that # do not break the loop, ESCALATES to a bounded pro-max exit-planner mentor (orchestrator-direct-invoke, # NOT forced tool_choice — dead on DeepSeek mid-history; the 4th sibling of the endturn-resolver family) # that reads the last loop calls + their outputs and returns VERDICT: REPLAN | RETIRE # . # [LEDGER 2026-09-07 @unreleased] DARK (default false) — BUILT + tsc-clean + loopToolBlock 6/6 + # loopExitPlanner 9/9 + orchestrator e2e 26/26 + LIVE-SEEDED FIRE-CHECK PASSED (seeded grep-loop: # block#1 → block#2 → ESCALATED → exit-planner RETIRE delivered, model complied + stopped retrying Bash). # Ships dark on the combined release; efficacy A/B still owed (retry_loop is the dominant TB2 fail class). #CORTEX_LOOP_TOOL_BLOCK=true # Escalation exit-planner mentor tuning (bounded pro-max; only consulted when CORTEX_LOOP_TOOL_BLOCK=true). #CORTEX_LOOP_TOOL_BLOCK_EFFORT=max # a bounded single-shot planner cannot grind #CORTEX_LOOP_TOOL_BLOCK_BUDGET_TOKENS=4000 # big enough that reasoning does not eat the plan on DeepSeek #CORTEX_LOOP_TOOL_BLOCK_TIMEOUT_MS=90000 # fail-open to the generic redirect on timeout # --- OPTIMAL LIFT CONFIG (appended) --- # [LEDGER 2026-09-02 @4.90.0] DEAD — no code path reads CORTEX_IDLE_TIMEOUT (grep packages/*/src = 0 hits); it was cargo-culted into the bench adapter env for months and removed there in adapter v21 (p3 timeout audit). Left commented so nobody re-adds it as a "lever". #CORTEX_IDLE_TIMEOUT=120