Repository navigation
ToggleLogic Free 2.2.0
·
22 commits
to main
since this release
Immutable
release. Only release title and notes can be modified.
2.2.0 — 2026-10-22
Milestone M1 part 1 — host adapters and the gateway-neutral Decision API, built
in the steps of docs/design/M1-HOST-ADAPTERS-AND-DECISION-API.md §7 (steps 1–5
and 8). OpenClaw routing is unchanged at every step. Behavior changes, all
below: the audit outcome for unchanged-model decisions (D28), the notification
interpreter default, and the new-session marker folder fix.
- Step 2 — injected paths, clock and state store (no behavior change).
New host-neutralsrc/core/paths.js(createPaths({ home, stateDir })),
src/core/clock.jsandsrc/core/state-store.js(atomic JSON documents;
a missing document reads as null, a corrupt one throws). The OpenClaw
adapter (src/adapters/openclaw/paths.js) resolves HOME and
OPENCLAW_STATE_DIRexactly as 2.1.x and injects onepathsobject into
the audit log, routing log, usage events, cost log, pricing cache, balances,
owner override, governed escalation and the Intelligence detector. A test
fails if anything undersrc/core/reads the environment, the OS home or
the host SDK. - Step 3 —
decide()extracted intosrc/core/decide.js(no behavior
change).createDecisionCore({ policy, services })runs the decision order
of design §4.3 on aDecisionRequest(requested,defaultRef,
candidates,fallbacks) and returns atogglelogic.decision/v1response
(decision,reason,rationale,engine). The OpenClaw interceptor is
nowtoDecisionRequest→decide→applyDecision; preflight caching,
duplicate-prompt suppression and session-store provenance stay in the
adapter, and host state is still read at the same point in the order.
Proof: a recorded-decision replay fixture (38 scenarios, every selection
reason, recorded from the step-2 code) must match exactly: return value,
routing record, audit events, usage events, warnings and seam calls. - Step 4 — OpenClaw adapter (no routing behavior change). Everything
OpenClaw-specific now lives insrc/adapters/openclaw/: the plugin entry
(entry.js,definePluginEntry), hook registration and service wiring
(register.js), the routing hook (interceptor.js), session-store
provenance (session-store.js), the conversation-access check and the
owner-override notification helper.src/index.jsonly carries the version
label and builds the adapter. The old module paths re-export the new ones, so
imports keep working. A test fails if OpenClaw-only code appears outside the
adapter. - Fixed: new-session marker folder. It now follows the same state-path
rules as every other ToggleLogic file (HOME, andOPENCLAW_STATE_DIRwith
~expansion). Before, a~/…state dir produced a literal~folder.
WithOPENCLAW_STATE_DIRunset the folder is unchanged. - Step 5 — Decision API v1 responses, decision matrix and replay.
decide()now returns a response that validates against
docs/design/schemas/decision-response.v1.schema.json: it adds
policyDigest(sha256:of the canonical policy JSON) andcostEstimate
(dollars for the model that will run, only when the caller supplies
usageEstimateand a pricing service; otherwisepriced: false,usd: null
and a namedunpricedReason— never a $0 stand-in), and omits empty
provider/modelinstead of sending null. The internalrecordedflag is
gone from the response. Newsrc/core/request.jsmaps a v1 wire request to
the core request;contentis never copied. New
togglelogic-decide replay --log <routing.jsonl> --config <file> [--json]
re-runs recorded routing decisions against a policy and prints the
differences (exit 2 when any differ). Records that depended on state the log
does not carry (owner override, the Intelligence seam, provider availability,
dispatch errors, or a host task label the log did not carry when the policy
routes on labels) are counted by reason, not guessed at. Replay reads only
and writes nothing. Invalid token counts and pricing-service errors give
invalid_usage_estimateandpricing_error;decide()never throws on a
cost estimate. Tests: a 112-row decision matrix (modes × requested source ×
provider availability) validates every request and response against the v1
schemas, requires the OpenClaw hook to return exactly the core's decision,
and proves request content never reaches a response, routing record, audit
event or warning. - Changed (D28): audit outcome for unchanged-model decisions. A
routing.decisionaudit event for a decision that leaves the model unchanged
is nownoop; 2.1.x reportedsuccesswhen the passthrough came from mode
dispatch (passthrough mode, no configured or cheap route, Intelligence
declined, shadow or unavailable). Routing is unchanged. The replay fixture
was re-recorded and differs from the step-2 recording only in that field, in
those 7 scenarios. - Step 8 — Changed: owner-override notification interpreter is
configurable. NewownerOverride.askInterpreter(defaultpython3,
resolved from the gateway'sPATH; a value containing/or starting with
~is a file path). 2.1.x always ran/usr/bin/python3; to keep exactly
that, setaskInterpreterto/usr/bin/python3. Only matters when
features.ownerOverrideAskis enabled. The plugin manifest accepts the new
key. - Step 8 — Deprecated:
src/enforcement/bounded-executor.js. It was never
wired into the plugin. It is now excluded from the npm package and stays in
the repository only for its tests; the next major removes it. - Fixed (tests only): the packaging check no longer spawns npm. The test
that proves the deprecated bounded executor stays out of the package now
asserts thefilesordering directly instead of runningnpm packin a child
process, which raced with other test files under parallel runs. The packed
file list itself is still verified bynpm pack --dry-runin every release
task. No product-code or behavior change.