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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ them (`v0.1.0` … `v1.19.0`); the 1.x ranges below are derived from that
history, not written from memory. Rust alpha and beta tags identify previews;
the stable 2.0 release has not been cut.

## 2.0.0-beta.77 — 2026-11-12

**Protected Codex hardening**

- Fix **`persist_execpolicy_amendment`** writing a durable allow rule from a stale approval answered after live auto tightened the turn to never. The rule is now committed under the same lock that publishes the switch, and refused once it has happened. New regression: `doxa_auto_refuses_an_execpolicy_amendment_answered_after_the_switch`.
- Pin and verify **`features.context_management=false`**. Experimental context management could re-enable the token budget at session start despite `features.token_budget=false`; startup now refuses unless both are off.
- Provider patch `376dc699` replaces `128293eb` on the same Codex 0.165.0 source. Docker sessions saved with the beta.76 provider resume only with beta.76; earlier 0.163.0 and 0.164.0 sessions are unaffected.

## 2.0.0-beta.76 — 2026-11-12

**Protected Codex 0.165.0**
Expand Down
42 changes: 21 additions & 21 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion rust/doxa-claude/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "doxa-claude"
version = "2.0.0-beta.76"
version = "2.0.0-beta.77"
edition = "2021"
publish = false
license = "AGPL-3.0-only"
Expand Down
2 changes: 1 addition & 1 deletion rust/doxa-codegraph/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "doxa-codegraph"
version = "2.0.0-beta.76"
version = "2.0.0-beta.77"
edition = "2021"
publish = false
license = "AGPL-3.0-only"
Expand Down
2 changes: 1 addition & 1 deletion rust/doxa-daemon/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "doxa-daemon"
version = "2.0.0-beta.76"
version = "2.0.0-beta.77"
edition = "2021"
publish = false
license = "AGPL-3.0-only"
Expand Down
2 changes: 1 addition & 1 deletion rust/doxa-daemon/tests/codex_legacy_protection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ query=read();assert query['method']=='initialize'
reply(query,{'userAgent':'doxa_codex_rs/__DOXA_SUPPORTED_CODEX_VERSION__ (doxa-precompact-fail-closed-v1; fixture)'})
assert read()['method']=='initialized'
args=sys.argv[1:];overrides=[args[i+1] for i,value in enumerate(args[:-1]) if value=='-c']
for flag in ['features.token_budget=false','features.async_compaction=false','agents.enabled=false','features.multi_agent_v2=false']:
for flag in ['features.token_budget=false','features.context_management=false','features.async_compaction=false','agents.enabled=false','features.multi_agent_v2=false']:
assert flag in overrides, flag
def merge(target, incoming):
for key,value in incoming.items():
Expand Down
2 changes: 1 addition & 1 deletion rust/doxa-daemon/tests/fixtures/codex_appserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def reply(request, value):

def fixture_config():
overrides = [sys.argv[i+1] for i, item in enumerate(sys.argv[:-1]) if item == '-c']
for flag in ('features.token_budget=false', 'features.async_compaction=false',
for flag in ('features.token_budget=false', 'features.context_management=false', 'features.async_compaction=false',
'agents.enabled=false', 'features.multi_agent_v2=false'):
assert flag in overrides, flag
def merge(target, incoming):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def merge(target, incoming):
if item == "-c":
merge(config, tomllib.loads(sys.argv[i + 1]))
assert config["features"]["token_budget"] is False
assert config["features"]["context_management"] is False
assert config["features"]["async_compaction"] is False
assert config["features"]["multi_agent_v2"] is False
assert config["agents"]["enabled"] is False
Expand Down
2 changes: 1 addition & 1 deletion rust/doxa-daemon/tests/fixtures/codex_live_auto.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def complete():

def fixture_config():
overrides = [sys.argv[i+1] for i, item in enumerate(sys.argv[:-1]) if item == '-c']
for flag in ('features.token_budget=false', 'features.async_compaction=false',
for flag in ('features.token_budget=false', 'features.context_management=false', 'features.async_compaction=false',
'agents.enabled=false', 'features.multi_agent_v2=false'):
assert flag in overrides, flag
def merge(target, incoming):
Expand Down
2 changes: 1 addition & 1 deletion rust/doxa-daemon/tests/fixtures/codex_peer_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def tool():

def fixture_config():
overrides = [sys.argv[i+1] for i, item in enumerate(sys.argv[:-1]) if item == '-c']
for flag in ('features.token_budget=false', 'features.async_compaction=false',
for flag in ('features.token_budget=false', 'features.context_management=false', 'features.async_compaction=false',
'agents.enabled=false', 'features.multi_agent_v2=false'):
assert flag in overrides, flag
def merge(target, incoming):
Expand Down
2 changes: 1 addition & 1 deletion rust/doxa-daemon/tests/fixtures/router_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def reply(row, value):

def fixture_config():
overrides = [sys.argv[i+1] for i, item in enumerate(sys.argv[:-1]) if item == '-c']
for flag in ('features.token_budget=false', 'features.async_compaction=false',
for flag in ('features.token_budget=false', 'features.context_management=false', 'features.async_compaction=false',
'agents.enabled=false', 'features.multi_agent_v2=false'):
assert flag in overrides, flag
def merge(target, incoming):
Expand Down
4 changes: 2 additions & 2 deletions rust/doxa-daemon/tests/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3963,7 +3963,7 @@ import json, sys, tomllib

def fixture_config():
overrides = [sys.argv[i+1] for i, item in enumerate(sys.argv[:-1]) if item == '-c']
for flag in ('features.token_budget=false', 'features.async_compaction=false',
for flag in ('features.token_budget=false', 'features.context_management=false', 'features.async_compaction=false',
'agents.enabled=false', 'features.multi_agent_v2=false'):
assert flag in overrides, flag
def merge(target, incoming):
Expand Down Expand Up @@ -5038,7 +5038,7 @@ source.parent.mkdir(parents=True,exist_ok=True)
if not source.exists(): source.write_text(json.dumps({'type':'session_meta','payload':{'id':'thread-1'}})+'\n')
def fixture_config():
overrides = [sys.argv[i+1] for i, item in enumerate(sys.argv[:-1]) if item == '-c']
for flag in ('features.token_budget=false', 'features.async_compaction=false',
for flag in ('features.token_budget=false', 'features.context_management=false', 'features.async_compaction=false',
'agents.enabled=false', 'features.multi_agent_v2=false'):
assert flag in overrides, flag
def merge(target, incoming):
Expand Down
2 changes: 1 addition & 1 deletion rust/doxa-engines/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "doxa-engines"
version = "2.0.0-beta.76"
version = "2.0.0-beta.77"
edition = "2021"
publish = false
license = "AGPL-3.0-only"
Expand Down
2 changes: 1 addition & 1 deletion rust/doxa-engines/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Assistant text and reasoning are bounded and scrubbed as complete messages. The

## Compaction protection

Protected sessions require DOXA's private **Codex 0.165.0** app server with contract `doxa-precompact-fail-closed-v1`. Before thread startup, DOXA checks the build identity, trusted synchronous `PreCompact` hook hash, and disabled token-budget and asynchronous compaction flags. The protected payload also refuses speculative background compaction internally, regardless of client feature overrides. Stock or unsupported app servers fail before creating or resuming a protected thread.
Protected sessions require DOXA's private **Codex 0.165.0** app server with contract `doxa-precompact-fail-closed-v1`. Before thread startup, DOXA checks the build identity, trusted synchronous `PreCompact` hook hash, and disabled token-budget, context-management and asynchronous compaction flags. The protected payload also refuses speculative background compaction internally, regardless of client feature overrides. Stock or unsupported app servers fail before creating or resuming a protected thread.

The hook binds the actual provider thread and owned rollout, prepares a scrubbed snapshot, and waits for the native LORE reviewer. Manual `/compact` independently reviews the same bound source and rechecks its identity and digest before submission. Missing, failed, timed-out, changed, asynchronous, or duplicate review blocks replacement; a worker exit code without an exact receipt is insufficient. DOXA also waits for matching hook and compaction events after submission. It does not overwrite global Codex settings or trust unrelated user hooks.

Expand Down
2 changes: 1 addition & 1 deletion rust/doxa-engines/src/bin/doxa-codex-protected.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use std::{

const SOURCE: &str = "360319d8dee62d87e2d59fc0c21805d79519cfed";
const CONTRACT: &str = "doxa-precompact-fail-closed-v1";
const PATCH: &str = "128293eb2e10aebdff916ab1d8fbce30fa10eba2dfac01cc501f9c1591034484";
const PATCH: &str = "376dc69901a97e62d19c6bf32377c4d464e93192340aa582d6992f2613f8ca46";
const MAX_BINARY: u64 = 1024 * 1024 * 1024;

#[derive(Deserialize)]
Expand Down
6 changes: 6 additions & 0 deletions rust/doxa-engines/src/codex_appserver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,12 @@ impl AppServerDriver {
if config["config"]["features"]["token_budget"] != false {
return Err(AppServerError::Protocol("Codex unhooked token-budget reset path is not disabled"));
}
// Experimental context management re-enables TokenBudget at
// session start for eligible accounts, regardless of the
// token_budget override. Require it explicitly off as well.
if config["config"]["features"]["context_management"] != false {
return Err(AppServerError::Protocol("Codex context management can re-enable the token-budget reset path"));
}
if config["config"]["features"]["async_compaction"] != false {
return Err(AppServerError::Protocol("Codex unreviewed asynchronous compaction path is not disabled"));
}
Expand Down
4 changes: 2 additions & 2 deletions rust/doxa-engines/src/codex_compact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::os::unix::fs::PermissionsExt;
pub const SUPPORTED_VERSION: &str = "0.165.0";
pub const PROTECTED_AGENT_PREFIX: &str = "doxa_codex_rs/0.165.0 (doxa-precompact-fail-closed-v1; ";
pub const SUPPORTED_SOURCE: &str = "360319d8dee62d87e2d59fc0c21805d79519cfed";
pub const SUPPORTED_PATCH: &str = "128293eb2e10aebdff916ab1d8fbce30fa10eba2dfac01cc501f9c1591034484";
pub const SUPPORTED_PATCH: &str = "376dc69901a97e62d19c6bf32377c4d464e93192340aa582d6992f2613f8ca46";

#[derive(serde::Deserialize)]
#[serde(deny_unknown_fields)]
Expand Down Expand Up @@ -200,7 +200,7 @@ impl CompactGate {
let group = format!("{{matcher={},hooks=[{{type=\"command\",command={},timeout={},async=false}}]}}",
string(MATCHER), string(&self.command), HOOK_TIMEOUT);
let state = format!("{}={{enabled=true,trusted_hash={}}}", string(HOOK_KEY), string(&self.hash));
vec!["features.codex_hooks=true".into(), "features.token_budget=false".into(), "features.async_compaction=false".into(), format!("hooks={{PreCompact=[{group}],state={{{state}}}}}")]
vec!["features.codex_hooks=true".into(), "features.token_budget=false".into(), "features.context_management=false".into(), "features.async_compaction=false".into(), format!("hooks={{PreCompact=[{group}],state={{{state}}}}}")]
}
/// Call `hooks/list` after initialize and BEFORE starting/resuming a thread.
/// Failure means this provider must not claim protected compaction.
Expand Down
2 changes: 1 addition & 1 deletion rust/doxa-engines/tests/codex_launcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use serde_json::json;
use sha2::{Digest, Sha256};
use std::{fs, os::unix::fs::PermissionsExt, process::Command};
const PATCH: &str = "128293eb2e10aebdff916ab1d8fbce30fa10eba2dfac01cc501f9c1591034484";
const PATCH: &str = "376dc69901a97e62d19c6bf32377c4d464e93192340aa582d6992f2613f8ca46";
fn fixture() -> tempfile::TempDir {
let dir = tempfile::tempdir().unwrap();
fs::set_permissions(dir.path(), fs::Permissions::from_mode(0o700)).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion rust/doxa-engines/tests/codex_protected.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ include!("fixtures/codex_protected_fixture.rs");

#[tokio::test]
async fn authoritative_version_and_hook_hash_refuse_before_thread_creation() {
for mode in ["version", "stock", "hash", "token-budget", "async-compaction", "native-agents", "native-agents-v2", "missing-agent-policy"] {
for mode in ["version", "stock", "hash", "token-budget", "context-management", "missing-context-management", "async-compaction", "native-agents", "native-agents-v2", "missing-agent-policy"] {
let (dir, options, gate) = fixture(mode);
assert!(AppServerDriver::spawn_protected(options, str::to_owned, false, gate).await.is_err());
assert!(!dir.path().join(format!("unsafe-after-{mode}")).exists());
Expand Down
5 changes: 3 additions & 2 deletions rust/doxa-engines/tests/fixtures/codex_protected_fixture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,12 @@ hooks=next(tomllib.loads(x)['hooks'] for x in overrides if x.startswith('hooks='
key=next(iter(hooks['state'])); command=hooks['PreCompact'][0]['hooks'][0]['command']
query=read(); assert query['method']=='config/read'
assert 'features.token_budget=false' in overrides
assert 'features.context_management=false' in overrides
assert 'features.async_compaction=false' in overrides
assert 'agents.enabled=false' in overrides
assert 'features.multi_agent_v2=false' in overrides
send({'id':query['id'],'result':{'config':{'agents':{'enabled':None if mode=='missing-agent-policy' else mode=='native-agents'},'features':{'token_budget':mode=='token-budget','async_compaction':mode=='async-compaction','multi_agent_v2':None if mode=='missing-agent-policy' else mode=='native-agents-v2'}},'origins':{},'layers':None}})
if mode in ('token-budget','async-compaction','native-agents','native-agents-v2','missing-agent-policy'):
send({'id':query['id'],'result':{'config':{'agents':{'enabled':None if mode=='missing-agent-policy' else mode=='native-agents'},'features':{'token_budget':mode=='token-budget','context_management':None if mode=='missing-context-management' else mode=='context-management','async_compaction':mode=='async-compaction','multi_agent_v2':None if mode=='missing-agent-policy' else mode=='native-agents-v2'}},'origins':{},'layers':None}})
if mode in ('token-budget','context-management','missing-context-management','async-compaction','native-agents','native-agents-v2','missing-agent-policy'):
if sys.stdin.readline(): Path('unsafe-after-'+mode).write_text('request')
sys.exit(0)
query=read(); assert query['method']=='hooks/list'
Expand Down
2 changes: 1 addition & 1 deletion rust/doxa-fleet/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "doxa-fleet"
version = "2.0.0-beta.76"
version = "2.0.0-beta.77"
edition = "2021"
publish = false
license = "AGPL-3.0-only"
Expand Down
Loading
Loading