Skip to content

fix: the first shadow window measured nothing it claimed to - #11

Merged
nayfly merged 1 commit into
mainfrom
fix/shadow-window-integrity
Aug 3, 2026
Merged

nayfly merged 1 commit into
mainfrom
fix/shadow-window-integrity

Conversation

@nayfly

@nayfly nayfly commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Two days of real traffic through the gateway, and all three exit criteria were wrong in a different way. None of this was visible without the traffic — which is what phase 1 is for.

process escalated on every call. OpenClaw groups it with exec under group:runtime, so tool_aliases mapped it to shell. But process does not run anything: it inspects and signals commands already running, carrying action, sessionId and timeout. Mapping it to shell inherited the requirement for a command it never sends, so the requirement could not be met and every call escalated on a missing parameter — three out of three in the window. Mapped to runtime now, with a test that also asserts exec still has to carry a command, because that is the whole reason shell asks for one.

The compose stack mounted the git working tree into the running engine. ./config:/app/config:ro meant every checkout, merge and branch switch swapped the policy underneath live traffic. Three distinct policy fingerprints appeared in two days, none from anyone editing a policy — one of them was my own git checkout main leaving the tree 46 commits behind while the container read it. A window that mixes fingerprints measures more than one engine, so it cannot be used, and nothing in the deployment made that visible.

The containers now read from deploy/policy/, a tracked directory with untracked contents: applying a policy is a deliberate make deploy_policy, and make deploy_policy_status shows drift against the repo. Git can no longer reconfigure a running engine as a side effect.

sufficient_window passed on no evidence. The criterion was decisions >= 10_000 or days >= 14, so fourteen idle days with three decisions cleared it — the same defect as a review gate that passes with nothing reviewed. It is now and. The count drops from 10 000 to 200 because the original number assumed production traffic: a single agent on one machine produces around fifteen decisions a day, and 10 000 under an and would mean roughly two years. The docs claimed "whichever is later" all along, so this is the code catching up to what was already written down.

Found while fixing that: the API coalesced thresholds with or DEFAULT, which reads an explicit 0 as "not supplied" — so the one value an operator sends to widen the window was the one value it ignored.

Replayed against the recorded window: 3 decisions loosened, all process, 0 tightened, no adversarial regression across 52 corpus cases.

Two days of real traffic through the gateway, and all three exit criteria were
wrong in a different way. None of this was visible without the traffic — which
is what phase 1 is for.

**`process` escalated on every call.** OpenClaw groups it with `exec` under
group:runtime, so tool_aliases mapped it to `shell`. But `process` does not run
anything: it inspects and signals commands already running, carrying `action`,
`sessionId` and `timeout`. Mapping it to `shell` inherited the requirement for
a `command` it never sends, so the requirement could not be met and every call
escalated on a missing parameter — three out of three in the window. Mapped to
`runtime` now, with a test that also asserts `exec` still has to carry a
command, because that is the whole reason `shell` asks for one.

**The compose stack mounted the git working tree into the running engine.**
`./config:/app/config:ro` meant every checkout, merge and branch switch swapped
the policy underneath live traffic. Three distinct policy fingerprints appeared
in two days, none from anyone editing a policy — one of them was my own
`git checkout main` leaving the tree 46 commits behind while the container read
it. A window that mixes fingerprints measures more than one engine, so it
cannot be used, and nothing in the deployment made that visible.

The containers now read from deploy/policy/, a tracked directory with untracked
contents: applying a policy is a deliberate `make deploy_policy`, and
`make deploy_policy_status` shows drift against the repo. Git can no longer
reconfigure a running engine as a side effect.

**`sufficient_window` passed on no evidence.** The criterion was
`decisions >= 10_000 or days >= 14`, so fourteen idle days with three decisions
cleared it — the same defect as a review gate that passes with nothing
reviewed. It is now `and`. The count drops from 10 000 to 200 because the
original number assumed production traffic: a single agent on one machine
produces around fifteen decisions a day, and 10 000 under an `and` would mean
roughly two years. The docs claimed "whichever is later" all along, so this is
the code catching up to what was already written down.

Found while fixing that: the API coalesced thresholds with `or DEFAULT`, which
reads an explicit 0 as "not supplied" — so the one value an operator sends to
widen the window was the one value it ignored.

Replayed against the recorded window: 3 decisions loosened, all `process`,
0 tightened, no adversarial regression across 52 corpus cases.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@nayfly
nayfly merged commit 1eefbb8 into main Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant