| id | 20260507-698664c-resume-followups |
|---|---|
| title | cbth Resume Follow-ups |
| status | completed |
| created | 2026-05-07 |
| updated | 2026-05-07 |
| branch | wip/cbth-resume-followups |
| pr | #45 |
| supersedes | |
| superseded_by |
- Complete the three follow-ups deferred from PR #43 in order: native resume cwd UX parity, canonical
permissionProfileread-side parsing, and soft Codex CLI version compatibility warnings. - Keep
cbth resume <thread-id> [-- <codex_args>]on the managed app-server / sidecar path while avoiding silent caller-cwd override when the operator did not provide--cd. - Treat
codex-cli 0.128.xas the currently validated range and warn, rather than fail, when the local Codex CLI reports a different or unparsable version.
cbth resumenow forwards a single explicit cwd only when--cd/-Cis supplied or an interactive cwd selection has been made. Non-interactive no-override resumes omit--cd, so the native resume path can preserve the previous thread cwd instead of forcing the caller cwd.- In interactive terminals,
cbth resumereads the previous thread cwd withthread/read(includeTurns=false)before startup materialization and prompts between the prior thread cwd and the current cwd when they differ. - The managed app-server lease refresher starts before any interactive cwd prompt, so an operator pause cannot let the app-server reservation expire before the foreground
codex resumeprocess launches. - Auto permission snapshots prefer
thread/resume.permissionProfilewhen available. LegacyapprovalPolicy/sandboxremains the fallback, and canonical/legacy disagreement on derived network or write permissions fails closed. - Startup, current, effective, and audit snapshot JSON now records the permission snapshot source and canonical profile body when present. Request-side
turn/startpinning still emits legacyapprovalPolicy/sandboxPolicybecause Codex 0.128 exposes canonical profile state on the read side while accepting legacy override fields. - Managed startup and
cbth doctor cliruncodex --version, report compatibility details, and warn when the local CLI is outside0.128.x; protocol parsing remains the fail-closed safety gate.
- Continue the broader CLI / daemon recovery backlog from current follow-ups.
- Revisit request-side exact permission-profile pinning only after Codex exposes a
turn/startoverride field for canonical profiles.
- Base:
698664cfrom PR #43; branch also mergesbcc86b7/v0.1.1before review. - Branch:
wip/cbth-resume-followups. - Review:
- Internal
codex-reviewon the initial branch range reported no blocking findings. - External bounded review found that the interactive cwd prompt could outlive the pre-refresher app-server lease; the follow-up fix starts lease refresh before cwd resolution and extends the no-
--cdresume test to assert the initial sidecarthread/resumeomitscwd. - Internal review then found a permission-profile/legacy write-scope mismatch hole; the fix now rejects canonical profiles whose write entries do not cover legacy writable roots, tmp access, or external sandbox shape.
- Internal
codex-readonlyfallback found thatthread/readcwd parsing only handled nestedthread.cwd, and that permission drift did not reportpermissionProfilebody changes. The final fix accepts both nested and top-level cwd response shapes and recordspermission_profiledrift when the canonical body changes. - Final internal
codex-readonlyreview onorigin/master..HEADreturnedLGTM. - Clean-context reviewer on PR #45 found that interactive resume cwd probing accepted
thread/readcwd without proving the response belonged to the requested thread. The fix now requires nestedthread.id, top-levelid, or top-levelthreadIdto explicitly match before using cwd, and treats missing/foreign ids as no history cwd so native no---cdfallback remains intact. - Codex PR review gate found that canonical
permissionProfileworkspace writes can usespecial.kind: "project_roots"in normal Codex 0.128 responses. The fix treats unsuffixedproject_rootsas covering legacy workspace writable roots while still rejecting narrowerproject_rootssubpaths as unrepresentable for legacy sandbox pinning. - A later clean-context review found four follow-up gaps: mixed-shape
thread/readcwd identity, permission-affecting--configforwarding, malformed canonicalpermissionProfileshapes, and nested-root drift direction. The next fix requires the cwd-bearing nested thread to carry a matching id, rejects known sandbox-scope config overrides, validates canonical profile object/network/fileSystem shapes strictly, and computes root drift by normalized containment instead of exact string-set subset checks. - Follow-up clean-context review found that the
--configguard missed canonical permission config roots. The guard now also rejectssandbox_permissions.*,permissions.*, and likely permission-profile aliases until those overrides can be represented in the sidecar's initialthread/resume. - Follow-up clean-context review found that read-only canonical profiles with nested
access: "none"denials were accepted even though automaticturn/startcan only emit legacy sandbox fields. The parser now fail-closes any canonical deny scope until exact permission profile pinning exists. - A further clean-context review found canonical read allow scopes could also be narrower than legacy readable roots. The parser now requires canonical read/write coverage to cover legacy
access/readOnlyAccessreadable roots before trusting a canonical profile. - Follow-up clean-context review found
--config default_permissions=...also selects a canonical permission profile while bypassing initial sidecar resume params. The managed resume config guard now rejectsdefault_permissions/default-permissions/defaultPermissions, and resume arg validation now runs before daemon startup so invalid forwarded args fail before managed flow setup. - Follow-up clean-context review found
--searchcould enable the nativeweb_searchtool in foreground Codex while the sidecar initialthread/resumestill recorded a no-network permission snapshot, and found nested cwd reads could ignore contradictory top-level thread ids. The latest fix rejects forwarded live web-search enablement until it can be represented in initial resume params and validates all presentthread/readids before using any cwd. - Follow-up clean-context review found direct foreground permission overrides, unrepresentable canonical read scopes, and mixed-id activity snapshots were still accepted. The latest fix rejects forwarded
--sandbox/--ask-for-approval/ danger-bypass plus matching config keys, fail-closes canonical read scopes that cannot be pinned with legacy sandbox fields, and validates all present ids on activity / turn-status snapshots. - GitHub Codex review and clean-context follow-up found web-search aliases and inline config tables could still bypass the deny list. The fix now treats
web_search_requestas live web-search and rejects top-levelfeatures, top-levelweb_search*, and top-level / nestedtools.web_search*managed-resume config overrides. - Follow-up clean-context review found Codex permission aliases and indirect config roots could still make foreground Codex diverge from the sidecar startup snapshot. The fix now rejects forwarded
--full-auto/--yoloaliases plus permission-affectingprofiles.*,projects.*, andtrust_levelconfig overrides. - Follow-up clean-context review found Codex options placed after the resume prompt were not scanned, so foreground Codex could still apply permission, web-search, cwd, or profile overrides that the sidecar did not mirror. Managed resume now fail-closes any forwarded option after the prompt unless the operator uses an explicit
--sentinel for literal prompt text. - Follow-up clean-context review found non-search feature toggles such as
use_legacy_landlock/request_permissionscould still be forwarded through--enable/--disableor equivalent config aliases without being carried in the sidecar's firstthread/resume. Managed resume now rejects all forwarded feature overrides and allfeatures.*/ top-level known feature config roots until feature state can be mirrored exactly. - Follow-up clean-context review found provider selection (
--oss/--local-provider) and unmirrored config keys such asmodel_reasoning_effortcould still let foreground Codex diverge from the sidecar's firstthread/resume. Managed resume now rejects provider overrides and only accepts config keys that are explicitly mirrored into initial resume params. - GitHub review-gate found TOML quoted config keys such as
"sandbox_mode"andtools."web_search".context_sizecould bypass the managed-resume deny list. Config key matching now normalizes quoted dotted key segments before deciding whether a key is mirrored, permission-affecting, or unsupported. - Follow-up clean-context review found native resume selector flags (
--last,--all,--include-non-interactive) could retarget foreground Codex independently of the managed bound thread id. Managed resume now rejects those selectors before daemon/app-server startup.
- Internal
- Validation:
cargo fmt --all -- --checkcargo clippy --locked --all-targets -- -D warningscargo test --lockedcargo test --locked thread_read_cwd_reads_nested_and_top_level_shapes --libcargo test --locked thread_read_cwd --libcargo test --locked permission_snapshot_rejects_malformed_permission_profiles --libcargo test --locked permission_drift_tracks_nested_workspace_roots_by_containment --libcargo test --locked permission_snapshot_rejects_permission_profile_denials_for_legacy_read_only --libcargo test --locked permission_snapshot_rejects_permission_profile_narrower_than_legacy_readable_root --libcargo test --locked permission_snapshot_accepts_project_roots_permission_profile_for_legacy_workspace_write --libcargo test --locked permission_snapshot_rejects_project_roots_subpath_for_legacy_workspace_write --libcargo test --locked cbth_resume_rejects_permission_affecting_config_overrides --test cli_run(including canonical permission config root cases)cargo test --locked cbth_resume_rejects_permission_affecting_config_overrides --test cli_runafter addingdefault_permissionsaliases to the rejection matrix.cargo test --locked thread_read_cwd_rejects_missing_or_foreign_thread_id --libcargo test --locked cbth_resume_rejects_forwarded_live_web_search --test cli_runcargo test --locked cbth_resume_rejects_forwarded_permission_policy_overrides --test cli_runcargo test --locked permission_snapshot_rejects_unrepresentable_permission_profile_read_scopes --libcargo test --locked thread_result_activity_snapshot_rejects_missing_or_foreign_thread_id --libcargo test --locked thread_result_turn_status_reads_top_level_turns_with_thread_metadata --libcargo test --locked cbth_resume_rejects_forwarded_live_web_search --test cli_runafter addingweb_search_requestaliases.cargo test --locked cbth_resume_rejects_permission_affecting_config_overrides --test cli_runafter addingfeatures/web_search/tools.web_searchaliases.cargo test --locked cbth_resume_rejects_forwarded_permission_policy_overrides --test cli_runafter adding--full-auto/--yoloaliases.cargo test --locked cbth_resume_rejects_permission_affecting_config_overrides --test cli_runafter addingprofiles.*/projects.*/trust_leveloverrides.cargo test --locked cbth_resume_rejects_post_prompt_forwarded_options --test cli_runcargo test --locked cbth_resume_rejects_forwarded_live_web_search --test cli_runafter broadening feature override rejection to all--enable/--disablevalues.cargo test --locked cbth_resume_rejects_permission_affecting_config_overrides --test cli_runafter broadening config rejection to allfeatures.*plususe_legacy_landlock/request_permissions.cargo test --locked cbth_resume_rejects_forwarded_provider_overrides --test cli_runcargo test --locked cbth_resume_rejects_unmirrored_config_overrides --test cli_runcargo test --locked cbth_resume_rejects_permission_affecting_config_overrides --test cli_runafter adding TOML quoted-key normalization cases.cargo test --locked cbth_resume_rejects_forwarded_thread_selectors --test cli_runcargo test --locked permission_drift_tracks_permission_profile_body_changes --libCARGO_TARGET_DIR=.codex-tmp/cargo-target-precommit git commit -S ...pre-commit hook passedcargo fmt --all,cargo clippy --locked --all-targets -- -D warnings, andcargo test --lockedin an isolated target directory after the shared target produced a cross-worktree binary mismatch.uv run python /Users/hoteng/.codex/skills/project-journal/scripts/project_journal.py validate --repo /Users/hoteng/.codex/worktrees/aef0/codex-background-task-handler