feat(parity): Wave E — settings persistence, exit_plan_mode, --fork-session, fallback signature strip, hermetic tests (v1.30.0)#119
Open
sweetcornna wants to merge 1 commit into
Open
Conversation
…ession, fallback signature strip, hermetic tests (v1.30.0) E1 Layered permission settings + console persist answer: - corlinman_agent.permission_settings: build_permission_gate() stacks <data_dir>/settings.json (user) -> ./.corlinman/settings.local.json (project) -> CORLINMAN_AGENT_PERMISSIONS env (final word); mode/strict follow the same precedence; byte-identical to from_env() when no file contributes. persist_allow_rule() writes durable allow rules atomically (tmp+rename, idempotent). ApprovalGate + servicer default gates now use the loader. - Console approval gains a third answer p/persist: allow + session cache + durable settings rule; a failing persist hook degrades to a session grant, never a deny. "a" stays session-scoped (Codex #104). E2 exit_plan_mode builtin (claude-code parity): - Model-callable plan->default flip with approval-cache reset across BOTH resolver sources (set_approval_resolver + app_state.approval_resolver); clean no-op outside plan mode; optional plan summary echo. - Child tool executor refuses exit_plan_mode: permission mode is servicer-global, only the top-level turn may end plan mode. - Skill allowed-tools control passthrough includes it so a skill can't strand the model in plan mode. E3 --fork-session (claude-code parity): - AgentJournal.fork_session copies only completed turns chronologically onto a fresh key (in_progress/errored skipped; per-turn best-effort; source read-only). Console flag mints a new console:<id> key and forks before resume; attach mode degrades with a note. E4 Cross-model thinking-signature strip on fallback: - Both reasoning-loop fallback branches (model-not-found, sustained overload) strip thinking/redacted_thinking blocks and signature keys from replayed history — per-model signatures otherwise turn a recoverable failover into a hard 400. E5 Hermetic tests: - Root conftest.py scrubs ANTHROPIC_BASE_URL + proxy env for non-live tests so host routing config can't reroute respx-mocked suites. Gate: ruff + mypy (595 files) + lint-imports + pytest 6708 passed / 4 skipped + ui typecheck/lint/build + gen-proto diff-clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Wave E — claude-code parity 小批量五连 (v1.30.0)
Gap ledger Wave E,五项独立小改动打包成一个 PR(每项都有自己的 TDD 红→绿轨迹)。
E1 — 分层权限设置持久化 + 控制台 persist 答案
问题:
PermissionGate.from_layered_sources零生产调用方——所有部署只从 env 建 gate,durable 规则只能写环境变量;控制台 "always" 授权随会话蒸发。corlinman_agent.permission_settings:build_permission_gate()按<data_dir>/settings.json(用户层)→<项目>/.corlinman/settings.local.json(项目层)→CORLINMAN_AGENT_PERMISSIONSenv(最终话语权)叠层;mode/strict同 precedence;无设置文件时与旧from_env()字节等价(含 first-match-wins 默认)。坏文件/坏块跳过不崩溃。ApprovalGate+ servicer 默认 gate 构造切到新加载器。p/persist:等同 always 并经persist_allow_rule原子写入(tmp+rename、幂等)用户层 settings;persist 钩子失败降级为会话级授权而非拒绝。a保持会话级(Codex Console permission surface: /permissions, /plan, --permission-mode + interactive approval (v1.23.0) #104——授权不越上下文边界)。E2 —
exit_plan_mode内置工具plan mode 拒掉全部 mutating 工具,此前只能人肉
/permissions放行。现在模型计划就绪自己调用:set_approval_resolver与app_state.approval_resolver——都重置);非 plan mode 干净 no-op;可选plan摘要回显。exit_plan_mode,只有顶层回合能结束 plan mode。E3 —
--fork-sessionAgentJournal.fork_session:仅复制 completed 回合、按时间序、消息/tool_calls 保真;in_progress(在别处直播)与errored(T4.4 面包屑)不复制;单回合损坏 log+跳过;源会话全程只读。Postgres 后端list_session_turns为 stub → 干净降级 0-turn fork(docstring 注明,含limit截断语义)。--fork-session:恢复前铸新console:<id>key 并 fork,原会话零污染;attach 模式回显不支持说明后继续不 fork。E4 — fallback 跨模型 thinking 签名剥离
thinking 块签名按模型铸造;OpenAI 兼容入口带入的客户端历史在 model-not-found / 持续过载两条 fallback 分支切模型重放时会把可恢复错误变成硬 400。两条分支重放前剥
thinking/redacted_thinking块与signature键(纯 thinking 内容折叠为"")。E5 — 测试封闭性
根
conftest.pyautouse fixture 对非 live 测试清洗ANTHROPIC_BASE_URL+ 6 个代理变量——宿主泄漏的路由 env 曾把 respx-mock 的 provider 套件重路由到真网络造成假失败。live_llm/live_transport不受影响;测试自身monkeypatch.setenv仍生效。验证
gen-proto.shdiff-clean备注
pyproject.toml版本与CHANGELOG.md头部预计有琐碎合并冲突(各 wave 均 bump),合并时按序取最高版本即可。exit_plan_mode二阶边缘与双 resolver 重置缺口已在本 PR 内预堵。