From a0a32021306a82e84ba5930c6ed9ca4d9f77744a Mon Sep 17 00:00:00 2001 From: PurpleCHOIms Date: Wed, 28 Oct 2026 00:00:24 +0900 Subject: [PATCH 1/2] test(web): verify terminal PTY behavior after footer copy retirement --- CHAGELOG.md | 2 ++ clients/web/src/lib/terminal-cli-boot.test.ts | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHAGELOG.md b/CHAGELOG.md index 140f57281..576a0f647 100644 --- a/CHAGELOG.md +++ b/CHAGELOG.md @@ -15,6 +15,8 @@ Keep proposed and unmerged changes out of released sections. ## [Unreleased] +- Proposed web terminal integration-test repair (PR link pending): wait for the rendered session/composer and verify real PTY draft persistence plus no agent-run submission, instead of waiting forever for the retired `connected` footer label. Keep all timeouts and the actual terminal/server flow. No product behavior change or release. + - Proposed workflow declared-edge commit validation ([#1131](https://github.com/BitterSecurity/Decepticon/pull/1131)): reject OPPLAN commits whose executable leaves declare no DAG edge (blocked_by, any_of or required_fact_ids) into stages named by the workflow's `depends_on` closure. The proof gate's reachable-leaf rule can never be satisfied for such edge-less plans, so they committed successfully and then blocked every objective transition and specialist dispatch with `workflow prerequisite stage incomplete on dependency path: ` — observed live on 2.2.0 where an edge-less red-team plan completed its scope objective and then could not start the discovery stage, could not repair itself through `commit_opplan` (completed objectives are immutable) and burned the recursion budget in a rejection loop. The gate's proof semantics are unchanged; the failure now surfaces at commit time with an actionable message naming the objective, its stage and the missing prerequisite stages. - Proposed step-budget async middleware fix ([#1130](https://github.com/BitterSecurity/Decepticon/pull/1130)): add `awrap_model_call` to `StepBudgetMiddleware` with a shared `_budget_note` helper so the sync and async paths stay identical. On 2.2.0, any engagement run invoked asynchronously (LangGraph background runs) crashed in the `model` node with `NotImplementedError: Asynchronous implementation of awrap_model_call is not available`, because `decepticon/middleware/step_budget.py` defined only the sync `wrap_model_call` and langchain's `AgentMiddleware` base raises on the missing async variant. Verified against a live 2.2.0 stack: an MCP `start_engagement` run failed in ~1.2 s before the first model call; with the patch the same call reaches the model and runs normally. Add async unit tests mirroring the sync budget cases (warn at 80%, hard stop at 100%, silent under budget, sync/async parity). diff --git a/clients/web/src/lib/terminal-cli-boot.test.ts b/clients/web/src/lib/terminal-cli-boot.test.ts index 9f41f4df0..152c712f0 100644 --- a/clients/web/src/lib/terminal-cli-boot.test.ts +++ b/clients/web/src/lib/terminal-cli-boot.test.ts @@ -11,7 +11,7 @@ import { fileURLToPath } from "node:url"; import { stripVTControlCharacters } from "node:util"; import { WebSocket } from "ws"; -test("web terminal boots the real CLI and renders its connected composer", { timeout: 120_000 }, async () => { +test("web terminal boots the real CLI and persists PTY input without starting a run", { timeout: 120_000 }, async () => { const root = await mkdtemp(join(tmpdir(), "terminal-cli-boot-")); await mkdir(join(root, "workspace", "loader-test", "plan"), { recursive: true }); await writeFile(join(root, "workspace", "loader-test", "plan", "roe.json"), JSON.stringify({ machine_enforcement: { in_scope: ["example.com"] } })); @@ -60,10 +60,10 @@ test("web terminal boots the real CLI and renders its connected composer", { tim socket!.on("message", data => { output += data.toString(); const plain = stripVTControlCharacters(output); - if (plain.includes("connected") && plain.includes("Enter send")) { clearTimeout(timer); resolve(plain); } + if (plain.includes("loader-test") && plain.includes("Enter send")) { clearTimeout(timer); resolve(plain); } }); socket!.once("error", error => { clearTimeout(timer); reject(error); }); - socket!.once("close", () => { clearTimeout(timer); reject(new Error(stripVTControlCharacters(output).slice(-1200))); }); + socket!.once("close", (code, reason) => { clearTimeout(timer); reject(new Error(`Terminal closed (${code}: ${reason.toString()}): ${stripVTControlCharacters(output).slice(-1200) || serverOutput}`)); }); }); assert.match(text, /loader-test/); assert.doesNotMatch(text, /SyntaxError|Unexpected token|EACCES/); From 8bb8b67481912ad2dee335cddf0af023da7f0f46 Mon Sep 17 00:00:00 2001 From: PurpleCHOIms Date: Wed, 28 Oct 2026 00:01:31 +0900 Subject: [PATCH 2/2] docs(changelog): link terminal integration-test PR 1135 --- CHAGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHAGELOG.md b/CHAGELOG.md index 576a0f647..977b69806 100644 --- a/CHAGELOG.md +++ b/CHAGELOG.md @@ -15,7 +15,7 @@ Keep proposed and unmerged changes out of released sections. ## [Unreleased] -- Proposed web terminal integration-test repair (PR link pending): wait for the rendered session/composer and verify real PTY draft persistence plus no agent-run submission, instead of waiting forever for the retired `connected` footer label. Keep all timeouts and the actual terminal/server flow. No product behavior change or release. +- Proposed web terminal integration-test repair ([#1135](https://github.com/BitterSecurity/Decepticon/pull/1135)): wait for the rendered session/composer and verify real PTY draft persistence plus no agent-run submission, instead of waiting forever for the retired `connected` footer label. Keep all timeouts and the actual terminal/server flow. No product behavior change or release. - Proposed workflow declared-edge commit validation ([#1131](https://github.com/BitterSecurity/Decepticon/pull/1131)): reject OPPLAN commits whose executable leaves declare no DAG edge (blocked_by, any_of or required_fact_ids) into stages named by the workflow's `depends_on` closure. The proof gate's reachable-leaf rule can never be satisfied for such edge-less plans, so they committed successfully and then blocked every objective transition and specialist dispatch with `workflow prerequisite stage incomplete on dependency path: ` — observed live on 2.2.0 where an edge-less red-team plan completed its scope objective and then could not start the discovery stage, could not repair itself through `commit_opplan` (completed objectives are immutable) and burned the recursion budget in a rejection loop. The gate's proof semantics are unchanged; the failure now surfaces at commit time with an actionable message naming the objective, its stage and the missing prerequisite stages.