From f58a1b7e86cd33f1d8ef68a3fe2f827202157386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Val=20Alexander=20=F0=9F=91=91?= Date: Fri, 30 Oct 2026 03:18:24 -0500 Subject: [PATCH 1/2] fix: verify disabled subagents before local admission --- .../main/engine/local-models/run-policy.ts | 2 + .../test/local-model-execution.test.ts | 4 ++ apps/desktop/test/local-run-policy.test.ts | 22 ++++++-- .../reviews/2026-10-30-lm5-subagent-policy.md | 13 +++++ .../config-receipt.json | 50 +++++++++++++++++++ docs/status.md | 2 + 6 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 docs/reviews/2026-10-30-lm5-subagent-policy.md create mode 100644 docs/reviews/2026-10-30-lm5-subagent-policy/config-receipt.json diff --git a/apps/desktop/src/main/engine/local-models/run-policy.ts b/apps/desktop/src/main/engine/local-models/run-policy.ts index 5d36cac0..1613d087 100644 --- a/apps/desktop/src/main/engine/local-models/run-policy.ts +++ b/apps/desktop/src/main/engine/local-models/run-policy.ts @@ -110,6 +110,8 @@ export function admitLocalConfiguration(read: ConfigRead, requirements: Requirem want("model_reasoning_summary", config.model_reasoning_summary ?? null, null); const features = record(config.features); want("features.view_image", features?.view_image ?? null, false); + want("features.multi_agent", features?.multi_agent ?? null, false); + want("features.multi_agent_v2", features?.multi_agent_v2 ?? null, false); const servers = record(config.mcp_servers); if (servers && Object.keys(servers).length) refuse(`MCP servers are configured (${Object.keys(servers).join(", ")}).`); return { sessionFlags, layers: summary, managedRequirements: false }; diff --git a/apps/desktop/test/local-model-execution.test.ts b/apps/desktop/test/local-model-execution.test.ts index 35a0dead..00cfeca5 100644 --- a/apps/desktop/test/local-model-execution.test.ts +++ b/apps/desktop/test/local-model-execution.test.ts @@ -279,6 +279,10 @@ test("a configuration another layer governs, managed requirements or a Codex wit const cases: [string, Parameters[0], RegExp][] = [ ["managed base_url", { configRead: r => { r.origins["model_providers.modex_local.base_url"] = { name: { type: "system", file: "/etc/codex/config.toml" }, version: "sha256:m" }; return r; } }, /the system configuration at \/etc\/codex\/config.toml sets `model_providers.modex_local.base_url`/], ["effective destination", { configRead: r => { r.config.model_providers.modex_local.base_url = "https://api.openai.com/v1"; return r; } }, /`model_providers.modex_local.base_url` is "https:\/\/api.openai.com\/v1"/], + ["enabled multi_agent", { configRead: r => { r.config.features.multi_agent = true; return r; } }, /`features\.multi_agent` is true/], + ["missing multi_agent", { configRead: r => { delete r.config.features.multi_agent; return r; } }, /`features\.multi_agent` is null/], + ["enabled multi_agent_v2", { configRead: r => { r.config.features.multi_agent_v2 = true; return r; } }, /`features\.multi_agent_v2` is true/], + ["missing multi_agent_v2", { configRead: r => { delete r.config.features.multi_agent_v2; return r; } }, /`features\.multi_agent_v2` is null/], ["requirements", { requirements: { allowedSandboxModes: ["read-only"] } }, /managed requirements/], ["old codex", { configRead: () => new Error("Method not found: config/read") }, /did not report its effective configuration \(Method not found: config\/read\)\. Local execution needs codex-cli 0.164.0 or later/], ]; diff --git a/apps/desktop/test/local-run-policy.test.ts b/apps/desktop/test/local-run-policy.test.ts index eaae1d95..7aa25ba2 100644 --- a/apps/desktop/test/local-run-policy.test.ts +++ b/apps/desktop/test/local-run-policy.test.ts @@ -6,20 +6,20 @@ const EXPECTED = { provider: "modex_local", origin: "http://127.0.0.1:18501", co const FLAGS = "sha256:b3932b4abe963781145150a5f8db02bf0afb5fe03385d52c15122db85463fce3"; const EMPTY = "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a"; -/** The shape codex-cli 0.164.0 returned for an LM-3 child on 2026-10-27 (docs/reviews/2026-10-27-lm5-destination-policy.md), trimmed to what the policy reads. */ +/** The shape codex-cli 0.164.0 returned for an LM-3 child on 2026-10-27 (docs/reviews/2026-10-27-lm5-destination-policy.md), trimmed to what the policy reads, with subagent flags verified by the 2026-10-30 codex-cli 0.166.0 configuration-only probe. */ function read(): ConfigRead { const flags = { model_provider: "modex_local", model_providers: { modex_local: { name: "Modex local", base_url: "http://127.0.0.1:18501/v1", wire_api: "responses", requires_openai_auth: false, env_key: "MODEX_LOCAL_TOKEN", request_max_retries: 0 } }, - model_context_window: 32768, web_search: "disabled", features: { view_image: false }, shell_environment_policy: { exclude: ["MODEX_LOCAL_TOKEN"] }, + model_context_window: 32768, web_search: "disabled", features: { view_image: false, multi_agent: false, multi_agent_v2: false }, shell_environment_policy: { exclude: ["MODEX_LOCAL_TOKEN"] }, }; const origin = { name: { type: "sessionFlags" }, version: FLAGS }; return { config: { model: null, model_provider: "modex_local", model_context_window: 32768, web_search: "disabled", model_reasoning_summary: null, openai_base_url: null, mcp_servers: {}, model_providers: { modex_local: { ...flags.model_providers.modex_local, experimental_bearer_token: null, auth: null, http_headers: null, env_http_headers: null, query_params: null } }, - features: { view_image: false, mentions_v2: true, remote_control: false }, file_opener: "vscode" }, + features: { view_image: false, multi_agent: false, multi_agent_v2: false, mentions_v2: true, remote_control: false }, file_opener: "vscode" }, origins: Object.fromEntries(["model_provider", "model_providers.modex_local.name", "model_providers.modex_local.base_url", "model_providers.modex_local.wire_api", "model_providers.modex_local.requires_openai_auth", - "model_providers.modex_local.env_key", "model_providers.modex_local.request_max_retries", "model_context_window", "web_search", "features.view_image", "shell_environment_policy.exclude.0"].map(k => [k, origin])), + "model_providers.modex_local.env_key", "model_providers.modex_local.request_max_retries", "model_context_window", "web_search", "features.view_image", "features.multi_agent", "features.multi_agent_v2.enabled", "shell_environment_policy.exclude.0"].map(k => [k, origin])), layers: [{ name: { type: "sessionFlags" }, version: FLAGS, config: flags }, { name: { type: "user", file: "/tmp/process-x/.codex/config.toml", profile: null }, version: EMPTY, config: {} }, { name: { type: "system", file: "/etc/codex/config.toml" }, version: EMPTY, config: {} }], }; } @@ -94,3 +94,17 @@ test("governed keys and layer descriptions", () => { assert.equal(describeLayer({ type: "sessionFlags" }), "Modex's session settings"); assert.equal(describeLayer({ type: "something_new" }), "a something_new configuration layer"); }); + +for (const flag of ["multi_agent", "multi_agent_v2"] as const) { + for (const value of [true, undefined, null, "false", { enabled: true }]) { + test(`local admission refuses ${flag}=${JSON.stringify(value) ?? "missing"}`, () => { + const reported = read(); + const features = reported.config.features as Record; + if (value === undefined) delete features[flag]; + else features[flag] = value; + assert.throws(() => admitLocalConfiguration(reported, { requirements: null }, EXPECTED), + error => error instanceof Error && error.message.includes(`features.${flag}`), + "unqualified native subagents must be refused before any thread opens"); + }); + } +} diff --git a/docs/reviews/2026-10-30-lm5-subagent-policy.md b/docs/reviews/2026-10-30-lm5-subagent-policy.md new file mode 100644 index 00000000..5b8ef3b9 --- /dev/null +++ b/docs/reviews/2026-10-30-lm5-subagent-policy.md @@ -0,0 +1,13 @@ +# LM-5 effective subagent admission — 2026-10-30 + +Issue #380 requires unqualified native subagents to stay disabled. LocalExecution already passes `features.multi_agent=false` and `features.multi_agent_v2=false`, but admission verified only the effective image flag. A pure-policy probe using a modified historical receipt admitted either subagent flag as true. This establishes a missing effective-value check, not observed native subagent execution. + +Admission now requires both effective subagent flags to be explicitly false. True, missing, null, string and object values are refused by key before a native thread opens. Existing layer/provenance, destination and credential checks remain in force. A CLI that omits either flag is refused rather than treated as qualified; product local execution remains unadmitted. + +A configuration-only probe of installed codex-cli 0.166.0 in a temporary empty home reported both flags false and their origins as session flags. `features list` also reported both stable and false. The probe created no thread, sent no prompts and ran no inference. Its [trimmed receipt](2026-10-30-lm5-subagent-policy/config-receipt.json) supports the reported configuration shape, not offline execution or qualification of older CLI versions. + +## Verification + +The clean baseline passed build and full unit checks (2,244 passes, 26 skips). Ten new pure-policy cases first failed because no exception was thrown. After the two effective-value checks, the focused policy/execution suites passed 26 tests with no failures or skips. Execution fixtures also verify that enabled and missing values produce a failed turn with no `thread/start`, no `turn/start` and no admitted provenance. Final `pnpm build && pnpm test` completed with exit 0: 2,254 passes, 26 skips and zero failures. Independent read-only review found no blocking findings. Protected delivery remains pending. + +Logs are preserved outside the worktree under `~/Documents/Codex/artifacts/modex-land-and-prune/lm5-subagent-*`. This repair addresses an admission invariant only. The native offline canary, full auxiliary matrix, capacity/runtime qualification, entry-point policy, context evidence and human acceptance remain open; #380 is not complete. diff --git a/docs/reviews/2026-10-30-lm5-subagent-policy/config-receipt.json b/docs/reviews/2026-10-30-lm5-subagent-policy/config-receipt.json new file mode 100644 index 00000000..d8744dc9 --- /dev/null +++ b/docs/reviews/2026-10-30-lm5-subagent-policy/config-receipt.json @@ -0,0 +1,50 @@ +{ + "cli": "0.166.0", + "scope": "configuration-only in temporary empty home; no thread or inference", + "features": { + "multi_agent_v2": false, + "network_proxy": null, + "multi_agent": false, + "api_key_cyber_access_programs": true, + "api_key_model_discovery": true, + "auth_elicitation": true, + "background_paginated_rollout_migration": false, + "codex_apps_mcp_2026_07_28": false, + "mcp_2026_07_28": false, + "mcp_connection_sharing": false, + "memories": false, + "mentions_v2": true, + "remote_control": false, + "remote_plugin": true, + "tool_suggest": true, + "windows_sandbox_service": false + }, + "origins": { + "features.multi_agent": { + "name": { + "type": "sessionFlags" + }, + "version": "sha256:a9409150a66a83ac8ffe500daa6eba5fe887b9beb82608cc9a59f0f8ddf58548" + }, + "features.multi_agent_v2.enabled": { + "name": { + "type": "sessionFlags" + }, + "version": "sha256:a9409150a66a83ac8ffe500daa6eba5fe887b9beb82608cc9a59f0f8ddf58548" + } + }, + "session_flags": [ + { + "name": { + "type": "sessionFlags" + }, + "version": "sha256:a9409150a66a83ac8ffe500daa6eba5fe887b9beb82608cc9a59f0f8ddf58548", + "config": { + "features": { + "multi_agent": false, + "multi_agent_v2": false + } + } + } + ] +} diff --git a/docs/status.md b/docs/status.md index b0583e26..95f496a9 100644 --- a/docs/status.md +++ b/docs/status.md @@ -227,6 +227,8 @@ The published application source is `2eda138` (v0.4.0). Later source deliveries ## In flight +- **LM-5 effective subagent admission.** A reproduced policy gap accepted enabled native subagent flags despite disabled launch settings. The repair requires both effective values to be false; ten regressions failed before the fix, and 26 focused policy/execution tests now pass, including refusal before a native thread opens. A configuration-only CLI 0.166.0 probe confirms the explicit false report shape. Build and full unit validation passed (2,254 passes, 26 skips); independent review found no blocking findings. Protected delivery remains pending; native qualification stays separate. [Evidence](reviews/2026-10-30-lm5-subagent-policy.md). + - **Markdown keyboard E2E sequencing repair.** A native scroll completion race reproduced in a blank Electron window. The proposed test waits for the rightward scroll to finish before reversing, preserving the original movement and accessibility assertions. Fresh build and unit validation passed (2,196 passed, 23 skipped), the focused E2E passed 15/15 across three themes, and independent review found no blockers. Protected delivery landed through #435 and is included in v0.4.0. [Evidence](reviews/2026-10-28-markdown-scroll-sequencing.md). - **Code Review packaged-app harness repair.** The shared harness and standalone IPC test now honor `MODEX_PACKAGED_APP`, including crash recovery. Two executable-identity regressions failed before the repair and passed afterward against a local ad-hoc bundle; development checks also passed. This is scoped harness evidence, not signed-release or human acceptance. [Evidence and remaining coverage limits](reviews/2026-10-28-code-review-packaged-harness.md). From 97d8ff6d15c4ecacbcdf9bba57b3fab12c64075e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Val=20Alexander=20=F0=9F=91=91?= Date: Fri, 30 Oct 2026 03:18:56 -0500 Subject: [PATCH 2/2] docs: separate local admission status from pending entries --- docs/status.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/status.md b/docs/status.md index 95f496a9..343614a1 100644 --- a/docs/status.md +++ b/docs/status.md @@ -227,14 +227,14 @@ The published application source is `2eda138` (v0.4.0). Later source deliveries ## In flight -- **LM-5 effective subagent admission.** A reproduced policy gap accepted enabled native subagent flags despite disabled launch settings. The repair requires both effective values to be false; ten regressions failed before the fix, and 26 focused policy/execution tests now pass, including refusal before a native thread opens. A configuration-only CLI 0.166.0 probe confirms the explicit false report shape. Build and full unit validation passed (2,254 passes, 26 skips); independent review found no blocking findings. Protected delivery remains pending; native qualification stays separate. [Evidence](reviews/2026-10-30-lm5-subagent-policy.md). - - **Markdown keyboard E2E sequencing repair.** A native scroll completion race reproduced in a blank Electron window. The proposed test waits for the rightward scroll to finish before reversing, preserving the original movement and accessibility assertions. Fresh build and unit validation passed (2,196 passed, 23 skipped), the focused E2E passed 15/15 across three themes, and independent review found no blockers. Protected delivery landed through #435 and is included in v0.4.0. [Evidence](reviews/2026-10-28-markdown-scroll-sequencing.md). - **Code Review packaged-app harness repair.** The shared harness and standalone IPC test now honor `MODEX_PACKAGED_APP`, including crash recovery. Two executable-identity regressions failed before the repair and passed afterward against a local ad-hoc bundle; development checks also passed. This is scoped harness evidence, not signed-release or human acceptance. [Evidence and remaining coverage limits](reviews/2026-10-28-code-review-packaged-harness.md). - **Notes history identity repair.** Repeated history toggles could duplicate revision rows or leave history visible after closing because the history and editor siblings shared a React key. The isolated `notes-history-identity` repair gives them distinct identities; three regression repetitions failed before the fix and passed afterward. Independent review found no blockers. Build and full unit/E2E checks passed (2,191 unit passed, 23 skipped; 470 desktop passed, seven skipped; seven site passed). Protected delivery landed in #429 (`7a01df2`); its successful merge-queue run passed 473 desktop tests with four skips and seven site tests. See [repair evidence](reviews/2026-10-28-notes-history-identity.md). +- **LM-5 effective subagent admission.** A reproduced policy gap accepted enabled native subagent flags despite disabled launch settings. The repair requires both effective values to be false; ten regressions failed before the fix, and 26 focused policy/execution tests now pass, including refusal before a native thread opens. A configuration-only CLI 0.166.0 probe confirms the explicit false report shape. Build and full unit validation passed (2,254 passes, 26 skips); independent review found no blocking findings. Protected delivery remains pending; native qualification stays separate. [Evidence](reviews/2026-10-30-lm5-subagent-policy.md). + - **LM-2 credential repair, included in v0.4.0.** PR #418 delivered the credential-copy and stale-discovery fixes from closed #401, together with isolation that prevents fake child PIDs from reaching OS signals, at `6c9000f`. Build, full unit tests, typechecks and the Electron IPC journey are recorded in the [reconciliation evidence](reviews/2026-10-26-lm2-credential-repair.md). This source delivery is separate from local-runtime qualification and product admission. - **v0.4.0 post-publication acceptance and Companion 0.4.0 (9).** Desktop publication is complete. The v0.3.0-to-v0.4.0 background upgrade remains unverified: the installed Mac already reports signed 0.4.0 and was left unchanged. Companion build 9 has not been delivered by this release session; its TestFlight upload and physical-device checks remain separate. Human accessibility, real-provider and native-platform account/session checks retain their existing gates. [Publication evidence and limits](reviews/2026-10-24-v0.4.0-release-review.md#published--2026-10-30-utc).