Repository navigation
fix: the first shadow window measured nothing it claimed to - #11
Merged
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.
processescalated on every call. OpenClaw groups it withexecunder group:runtime, so tool_aliases mapped it toshell. Butprocessdoes not run anything: it inspects and signals commands already running, carryingaction,sessionIdandtimeout. Mapping it toshellinherited the requirement for acommandit 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 toruntimenow, with a test that also assertsexecstill has to carry a command, because that is the whole reasonshellasks for one.The compose stack mounted the git working tree into the running engine.
./config:/app/config:romeant 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 owngit checkout mainleaving 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, andmake deploy_policy_statusshows drift against the repo. Git can no longer reconfigure a running engine as a side effect.sufficient_windowpassed on no evidence. The criterion wasdecisions >= 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 nowand. 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 anandwould 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.