← All engines · Pipeline
TrustLadder
stable
v1.0.0 · last updated 2026-06-06 · source: cybercli.bridge.trust_ladder.TrustLadder
§1
What it does
Owns the per-action-template Trust Level (L0-L7) — the operator-set dial that the AuthorityBridge resolves against when deciding what to do with every AI proposal.
§2
Why you care
The TrustLadder is the surface where you set how much rope the AI gets. Each action template — `notify_only.v1`, `wazuh.isolate_agent.v1`, `m365.disable_user.v1`, every one — gets its own level. The bridge then takes the strictest of (this dial, your tier ceiling, the action's manifest risk-lock, your license per-category ceiling) when an action shows up. The dial is yours; the ceilings are guardrails.
Other AI security products either ship one global on/off (Microsoft Copilot, Charlotte AI) or a fixed scale that you cannot edit per action (Prophet, Dropzone). CyberCLI is the only product where you can set notify_only.v1 to L7 (silent autonomous fire) while keeping wazuh.isolate_agent.v1 at L3 (proposes, you approve) — and watch the calibration log build the case for promoting isolate_agent over the next 90 days.
The dial also persists across restarts and is process-safe — multiple ingest workers + the dashboard can read and write simultaneously without races. A wedged lock auto-stales after 30 seconds so a crashed worker can't deadlock the rest of the system into never reading the ladder again.
§3
How it works
TrustLadder stores per-action-template levels in a JSON file under the data dir (`trust_ladder.json`). On disk the file is one flat dict `{action_template_id: level}`. The module exposes `get_level(atid)` / `set_level(atid, level)` and a `snapshot()` view that the dashboard consumes.
Reads and writes are guarded by a file lock with a hardening-pass stat-identity check: if the lockfile is older than 30 seconds AND its (mtime_ns, size, inode) tuple is unchanged across a re-poll, the lock is treated as orphaned and reclaimed. That hardening was added after a v0.4 incident where a crashed dashboard worker held the lock forever; the test for it lives in `tests/test_hardening14.py`.
Defaults are deliberate. Templates in `_DEFAULT_L7_TEMPLATES = {notify_only.v1, evidence_collect.v1, case_open.v1}` default to L7 — these are read-only / additive actions whose externality is owned by the dispatcher or the case writer, not the executor stage. Every other unknown template defaults to L3 — propose only — so a buyer who configures a custom template never accidentally gives their AI autonomy on it.
When the dashboard's `/trust-ladder` page writes a new level, the lock is acquired, the JSON is atomically rewritten (write to `trust_ladder.json.tmp`, fsync, rename), the lock releases, and the next gate decision reads the new value. There is no in-memory cache the bridge has to refresh — every gate decision re-reads the JSON. That's a deliberate tradeoff for correctness over throughput; v1's per-event volume is well below the read budget.
§4
Configure & observe
CLI
$ cybercli doctor Spot-checks that the ladder file is readable, the lock works, and the defaults line up with the manifest registry.
$ cybercli audit tail -n 20 The bridge writes the resolved `trust_level_applied` + `effective_level` on every gate row — read recent rows to see the ladder in action against real events.
Dashboard surfaces
The operator-facing dial. Per-template card with current level + tier ceiling + risk-lock ceiling + license ceiling, and a slider to change the configured level.
The calibration log — every event where the bridge queued an action under your current ladder. Watch the ratio of approved vs rejected to build the case for promotion.
Audit row shape
trust_level_recordedtrust_level_changed parameters.action_template_id + parameters.previous_level + parameters.new_level + parameters.actor on every set_level call. The bridge's own audit rows carry trust_level_applied (the ladder's value) and effective_level (after ceilings).
§5
Status
Stable — the ladder file format has been frozen since 2026-04-15 and has not needed a migration. The lock implementation passed a 1000-worker concurrency stress test in `tests/test_trust_ladder_concurrency.py` without a single race.
Shipped 2026-06-07 (recommender API half): `cybercli.bridge.promotion_recommender.compute_recommendations(audit_log_entries)` walks the human-verdict slice of the audit chain and returns ranked promotion candidates with rationale (e.g. '19/20 approvals at L3 — meets the ≥95% promotion bar'). Tunable thresholds for min_decisions + approval_rate + per-template ceilings. The /trust-ladder dial UI that calls this on every render + the operator confirm flow that writes the new level via the existing set_level() path ship in v1.x.
Known limit: there is no per-tenant ladder yet. Single-instance installs share one ladder; multi-tenant federation (v1.5 + Sovereign role) gets per-tenant ladders. This is on the v1.5 roadmap, not v1.
How this engine talks to the rest