- name
- agent-degraded-output-suspect-execution-environment
- description
- When a capable agent first declares a STRONG plan/contract/approach then a retry or continuation produces a WEAKER one, suspect the execution environment couldn't run the strong version โ not model laziness or a prompting gap.
# Agent declares strong, then degrades โ suspect the execution environment
## Problem
An LLM agent with a declareโexecute split (declares a verification
contract / a plan / a tool sequence, then carries it out) produces a
**weak** final artifact. The obvious first hypothesis โ "the model is
lazy / the prompt is too soft / it doesn't follow instructions" โ is
often **wrong**.
- ์ฆ์: the agent declares something strong (`pytest`, a real test
command, a thorough plan), the run fails or hits a round cap, and a
retry / continuation re-declares a **weaker** version (`py_compile`,
an `import`-only check, a trivial plan) that *does* pass.
- ๊ทผ๋ณธ ์์ธ: the strong version was **un-runnable in the agent's
execution environment** โ a missing toolchain, a read-only path, a
permission wall, a placeholder that didn't resolve. The agent ran
the strong command, saw it fail, and *rationally* degraded to
something the broken environment could satisfy.
- ํํ ์คํด: blaming prompt strength โ you strengthen the prompt, the
agent declares strong AGAIN, it still can't run it, and it degrades
AGAIN. Prompt engineering cannot fix an environmental wall.
Real case (BSNexus, 2026-05): the work LLM's `shell_exec` ran in a
backend container with no `pytest`/`ruff`. qwen3 declared a strong
`pytest` contract (A1 prompt work succeeded), spent 36 rounds unable
to run it (`pip install` blocked โ read-only site-packages), hit the
loop cap; the Tier-1 continuation then re-declared an `import`-only
contract that matched the broken environment. The deliverable reached
`verified` with its tests never run. The fix was environmental (give
the work phase the toolchain โ a sandbox), not prompting.
## Solution
When you see declare-strong-then-degrade, **diagnose the environment
before touching the prompt**:
1. Take the STRONG thing the agent declared on the first attempt and
run it *yourself*, by hand, in the exact environment the agent
runs in (same container, same user, same cwd, same PATH).
2. If it fails โ missing binary (exit 127), `Permission denied`,
read-only FS, an unresolved `<placeholder>` token โ that is the
root cause. The agent isn't lazy; it's adapting to a broken env.
3. Fix the environment (install the toolchain, fix ownership, resolve
the placeholder, mount the volume) โ not the prompt.
4. Re-verify: the agent should now declare strong AND the strong
version should run.
Inspect the agent's tool-call trace (e.g. `tool_events`): a run that
shows the agent *trying* the strong command, getting errors, then
`pip install` attempts, then falling back โ is the signature.
## Key Insights
- A capable agent degrading its own output is usually **rational
adaptation to a broken environment**, not a compliance failure. The
agent saw the strong path fail and routed around it.
- The declareโexecute split makes this sneaky: the *declaration* looks
fine (prompt worked), so you don't suspect the prompt is innocent.
The break is between declare and execute.
- Prompt engineering has a hard ceiling here โ re-nudging a model to
declare strong does nothing when the environment can't run strong.
Same family as `local-llm-runtime-nudge-ceiling`.
- First diagnostic move: **run the agent's own first-attempt strong
command by hand in its environment.** One command tells you env-vs-
prompt.
## Red Flags
- A retry / continuation / fallback attempt produces a *simpler* or
*weaker* artifact than the first attempt.
- The agent's trace shows it tried tool/command X, got an error, then
switched to a weaker Y.
- `pip install` / `npm install` / `apt` attempts mid-run (the agent
is trying to repair a missing toolchain itself).
- "The model just won't do X" after you've already strengthened the
prompt once.
- A verification / gate passes via a check that doesn't actually
exercise the deliverable (compile-only, import-only, `--help`).
---
## ์ฌ์ด ์ฆ์ โ "๊ฒ์ผ๋ฅธ ์์ด์ ํธ"๊ฐ ์ฌ์ค์ **์ ๋ ํ๋ฅ ๋จ๊ณ**์ผ ๋
์์ ๋ด์ฉ์ *ํ ๋ฐ ์์์* strongโweak ๋ก ๋จ์ด์ง๋ ๊ฒฝ์ฐ๋ค. ๋ค๋จ๊ณ ํ์ดํ๋ผ์ธ
(designโimpl, planโbuild, extractโtransform)์๋ **๊ฐ์ ์ค์ง์ ๋ค๋ฅธ ๋ชจ์**์ด ์๋ค:
- **์ฆ์**: ์ฝ๋๋ฅผ ์์ฒญํ๋๋ฐ **๋ช
์ธ ๋ฌธ์ ํ๋**๊ฐ ๋์ค๊ณ ๋ฐ์ `verified` / ์๋ฃ๋ก ๋๋๋ค.
"์์ด์ ํธ๊ฐ ์ผ์ ํํผํ๋ค / ์ง์๋ฅผ ์ ๋ฐ๋๋ค" ๋ก ์ฝํ๋ค.
- **์ค์ **: ์๋ฅ ๋จ๊ณ(design)๋ **์ ์ผ์ ์ ํํ ํ๋ค.** ๋ช
์ธ๋ฅผ ์ฐ๋ ๊ฒ ๊ทธ ๋จ๊ณ์ ์ฐ์ถ๋ฌผ์ด๋ค.
๊นจ์ง ๊ฒ์ **ํ๋ฅ ๋จ๊ณ(impl)๊ฐ ์์ ์คํฐ๋์ง ์์ ๊ฒ**์ด๋ค.
### ์ ์ค์งํ๊ธฐ ์ฌ์ด๊ฐ
ํ์ดํ๋ผ์ธ์ด ์ด์ ์์ ๋์ ์ฃฝ์์ ๋์ **์๋ฅ ์ฐ์ถ๋ฌผ์ด ์์ ํ ๋์ผ**ํ๋ค.
์ฐจ์ด๋ "๊ทธ ๋ค์์ ๋ฌด์์ด ์๊ฒผ๋" ๋ฟ์ธ๋ฐ, ์ฌ๋์ ๋์์ ์ฐ์ถ๋ฌผ๋ง ๋ณธ๋ค.
๊ฒ๋ค๊ฐ ์๋ฅ ๋ฐ์ ์ ์ ์ข
๋ฃ๋ผ **์๋ฌ๋ ๋ก๊ทธ๋ ์๋ค.**
### ๋จผ์ ํ์ธํ ๊ฒ (์์ด์ ํธ๋ฅผ ์์ฌํ๊ธฐ ์ ์)
```sql
-- 1) ์ด ๋ฐ์ ๋ค๋จ๊ณ๋ก ๋ถ๋ฅ๋๋?
select payload->'frame'->>'pipeline', payload->>'stage' from execution_runs where id = '<run>';
-- 2) ํ๋ฅ ๋ฐ์ด ์ค์ ๋ก ์๊ฒผ๋?
select count(*) from execution_runs where payload->>'design_run_id' = '<run>';
-- 3) ๊ฐ์ ์ถ์ผ๋ก ์๊ณ์ด โ ์ธ์ ๋ถํฐ ์ ์๊ฒผ๋?
select created_at::date, count(*) from execution_runs
where payload ? 'design_run_id' group by 1 order by 1;
```
3๋ฒ์ด ๊ฒฐ์ ์ ์ด๋ค. **์ด์ ๊น์ง ๋๋ ๊ฒ ์ค๋ 0์ด๋ฉด ์์ด์ ํธ ๋ฌธ์ ๊ฐ ์๋๋ค.**
### ์ค์ ์ฌ๋ก (BSVibe, 2026-08-18)
`worker_runtime.py` ๋ฆฌํฉํฐ๋ง์ ์์ฒญํ๊ณ (*"์์ ๋ฆฌํฉํฐ๋ง, ๋์ ๋ณ๊ฒฝ ๊ธ์ง, ๊ธฐ์กด ํ
์คํธ
์ ๋ถ ํต๊ณผ๊ฐ ์๋ฝ ์กฐ๊ฑด"*) `spec_..._split.md` ํ๋๊ฐ ๋์๋ค. ์ฒ์์ **์์ด์ ํธ์ ํํผ**๋ก
์ง๋จํ๊ณ "์ฐ๋ฌธ ์ฐ์ถ๋ฌผ" ๊ฒ์ฌ๋ฅผ ์กฐ์ด๋ ์์ ์ ์ฐฉ์ํ๋ค โ **ํ๋ ธ๋ค.**
์๊ณ์ด์ ์ธ๋ ์ฒด์ด๋๋ impl ๋ฐ์ด **์ ๋ 1๊ฑด โ ๋น์ผ 0๊ฑด**. ์ ๋ ์ญ์ ๋ ๋ผ์ฐํ
๋ฃฐ์ด
์ฒด์ด๋ ๊ฒ์ดํธ์ ์๋ฌต์ ํผ์ฒ ํ๋๊ทธ์๋ค.
โ `deleting-inert-config-row-disables-hidden-feature`
**์ฐฉ์ํ๋ "ํํผ ๋ฐฉ์ง" ์์ ์ ํ๊ธฐํ๋ค.** ๊ทธ ์์ ์ ๋ฃ์์ผ๋ฉด ์ ์์ ์ธ design ๋จ๊ณ
์ฐ์ถ๋ฌผ๊น์ง ์ ๋ถ ์ฌ๋์ ํธ์ถํ๋ **๊ณผ์ ํํน**์ด ๋์ ๊ฒ์ด๋ค(์ญ๋ ํํน 8๊ฑด ์ค 4๊ฑด์ด
๋ฐ๋ก ๊ทธ ์ ๋นํ design ๋จ๊ณ์๋ค).
> **๊ตํ: ์์ด์ ํธ๋ฅผ ๊ณ ์น๋ ์์ ์ ์ฐฉ์ํ๊ธฐ ์ ์, ๊ทธ ์ฐ์ถ๋ฌผ์ด "์ด๋ ๋จ๊ณ์ ์ ์ ์ฐ์ถ๋ฌผ"
> ์ธ์ง๋ถํฐ ํ์ธํ๋ผ.** ๋จ๊ณ๋ฅผ ๋ชจ๋ฅธ ์ฑ ์ฐ์ถ๋ฌผ๋ง ๋ณด๋ฉด ์ ์์ ๊ฒฐํจ์ผ๋ก ์ฝ๋๋ค.
View on GitHub