mirror of
https://github.com/hanzoai/bot-formal-models.git
synced 2026-10-30 18:46:45 +00:00
7.2 KiB
7.2 KiB
Formal models review pack (human-auditable)
This document is intended to make it easy to independently verify that the TLA+ models in this repo are:
- non-vacuous (they actually constrain something)
- traceable to the OpenClaw implementation
- reproducible (green passes, negative fails for the right reasons)
How to use this pack
1) Repro run (recommended)
Run from a clean checkout:
make precedence groups elevated nodes-policy attacker approvals approvals-token nodes-pipeline \
gateway-exposure gateway-exposure-v2 gateway-exposure-v2-protected \
gateway-auth-conformance gateway-auth-tailscale gateway-auth-proxy \
pairing pairing-cap pairing-idempotency pairing-refresh pairing-refresh-race \
ingress-gating ingress-idempotency ingress-dedupe-fallback ingress-trace ingress-trace2 \
routing-isolation routing-precedence routing-identitylinks routing-identity-transitive routing-identity-symmetry routing-identity-channel-override \
routing-thread-parent discord-pluralkit group-alias-check
Negative suite (expected failures):
make -k precedence-negative groups-negative elevated-negative nodes-policy-negative \
attacker-negative attacker-nodes-negative attacker-nodes-allowlist-negative attacker-nodes-allowlist-negative \
approvals-negative approvals-token-negative nodes-pipeline-negative \
gateway-exposure-negative gateway-exposure-v2-negative gateway-exposure-v2-protected-negative \
gateway-exposure-v2-unsafe-custom gateway-exposure-v2-unsafe-tailnet gateway-exposure-v2-unsafe-auto \
gateway-auth-conformance-negative gateway-auth-tailscale-negative gateway-auth-proxy-negative \
pairing-negative pairing-cap-negative pairing-idempotency-negative pairing-refresh-negative pairing-refresh-race-negative \
ingress-gating-negative ingress-idempotency-negative ingress-dedupe-fallback-negative ingress-trace-negative ingress-trace2-negative \
routing-isolation-negative routing-precedence-negative routing-identitylinks-negative routing-identity-transitive-negative routing-identity-symmetry-negative routing-identity-channel-override-negative \
routing-thread-parent-negative discord-pluralkit-negative
Expected outcomes:
- Green suite: exit 0
- Negative suite: non-zero exit (because each negative target should find an invariant violation)
2) “Not AI slop” sanity checks
For each harness you care about:
- Confirm it has a clear invariant (not a tautology)
- Confirm
ASSUMEdoes not trivialize the invariant - Confirm the negative version changes one thing and causes TLC to fail
Traceability map (models ↔ code)
The code references below are implementation locations you can inspect. The models are abstractions (not full-code verification).
Tool policy: precedence + group expansion
- Models:
tla/specs/ToolPolicyPrecedence.tla(+_BadAllowOverrides)tla/specs/ToolGroupExpansion.tla
- What it checks:
- deny-wins monotonicity
- group expansion exactness (e.g. group:memory contains expected tools)
- OpenClaw code:
openclaw/src/agents/tool-policy.ts- Conformance snapshot used for extraction:
openclaw/src/agents/tool-policy.conformance.ts
Elevated gating (exec approvals / sensitive operations)
- Models:
tla/specs/ElevatedGating.tla(+_BadOr)
- What it checks:
- elevated mode requires correct gating combination (no “OR” bug)
- Code:
- OpenClaw tool invocation + approvals pipeline (see nodes + approvals harnesses)
Nodes command policy + approvals pipeline
- Models:
tla/specs/NodesCommandPolicy.tla(+_BadNoDeclareCheck)tla/specs/AttackerHarness_Approvals.tla(+_BadIgnoresApproval)tla/specs/AttackerHarness_ApprovalsToken.tla(+_BadReplay)tla/specs/NodesPipelineHarness.tla(+_BadReplay)
- What it checks:
- shared-channel attacker can’t execute nodes.run without: declaredCommands + approval (+ tokenized)
- Code concepts:
- nodes tool (
nodes.run) policy + approvals lifecycle
- nodes tool (
Gateway exposure + auth
- Models:
tla/specs/GatewayExposureHarness.tla(safe/unsafe configs)tla/specs/GatewayExposureHarnessV2.tla(safe/protected/unsafe configs)tla/specs/GatewayAuthConformanceHarness.tla(safe/unsafe)tla/specs/GatewayAuthTailscaleHarness.tla(+_BadSpoof)tla/specs/GatewayAuthTrustedProxyHarness.tla(+_BadSpoof)
- What it checks:
- non-loopback bind requires auth
- spoof protections for trusted proxy / tailnet
- Code:
openclaw/src/gateway/auth.ts
Pairing store invariants
- Models:
tla/specs/PairingStoreHarnessV2.tla(+_BadExpiry,_BadNoCap)tla/specs/PairingStoreIdempotencyHarness.tla(+_BadDuplicates)tla/specs/PairingStoreRefreshEnabledHarness.tla(+_BadCapOnRefresh)tla/specs/PairingStoreRefreshRaceHarness.tla(+_BadNonAtomic)
- What it checks:
- expiry, max pending cap, idempotency, refresh races
- Code:
openclaw/src/pairing/*
Ingress gating + idempotency + trace
- Models:
tla/specs/IngressGatingHarness.tla(+_BadBypass)tla/specs/IngressEventIdempotencyHarness.tla(+_BadNoDedupe)tla/specs/IngressDedupeKeyFallbackHarness.tla(+_BadNoFallback)tla/specs/IngressMultiMessageTraceHarness.tla(+_BadMissingTrace)tla/specs/IngressMultiEventTraceHarness.tla(+_BadCrossStream)
- What it checks:
- unauthorized can’t bypass
- dedupe prevents duplicate emits
- trace correlation rules
- Code concepts:
- inbound processing, dedupe keys, trace propagation
Routing invariants
- Models:
tla/specs/RoutingIsolationHarness.tla(+_BadAlwaysMain)tla/specs/RoutingPrecedenceHarness.tla(+_BadIgnoresChannelOverride)tla/specs/RoutingIdentityLinksHarness.tla(+_BadCanonical)tla/specs/RoutingIdentityLinksTransitiveHarness.tla(+_BadNonTransitive)tla/specs/RoutingIdentityLinksSymmetryHarness.tla(+_BadAsymmetric)tla/specs/RoutingIdentityLinksChannelOverrideHarness.tla(+_BadIgnoresChannelDisable)
- Code:
openclaw/src/routing/*
NEW: routing thread parent binding inheritance
- Models:
tla/specs/RoutingThreadParentBindingHarness.tla(+_BadThreadLoses)
- What it checks:
- explicit thread binding beats parent binding
- otherwise parent binding is inherited
- Code:
openclaw/src/routing/resolve-route.ts(matchedBy="binding.peer.parent")openclaw/src/discord/monitor/message-handler.preflight.ts(passes parentPeer)
NEW: Discord PluralKit sender identity resolution
- Models:
tla/specs/DiscordPluralKitIdentityHarness.tla(+_BadWebhookPK)
- What it checks:
- PluralKit resolution does not apply to webhook messages
- allowlist is applied to the resolved sender kind
- Code:
openclaw/src/discord/pluralkit.tsopenclaw/src/discord/monitor/sender-identity.tsopenclaw/src/discord/monitor/message-handler.preflight.ts
Known limitations (explicitly acknowledged)
- Many harnesses are static constraint checks (trivial
Next). This is fine for precedence/ resolution invariants, but not a full temporal model. - TLC model checking is bounded to finite state spaces defined by the constants.
- These models are not full-code proofs; they are abstractions tied to code by traceability + conformance tooling.