sec(door): closed by default, governor fails closed; self-authoring off by default
deploy / test (push) Successful in 5m15s
deploy / build (push) Successful in 5m28s

Three fail-open paths on the §15 door: no env at all meant allow-all; a
governor that could not be reached approved with a WARNING; and a reply
that never said DENY — empty, truncated, a refusal — approved, because the
rule was !contains("DENY"). On the two days the judge plan emptied every
outbound action was approved by nobody.

Now: governor_allows() needs an explicit ALLOW and no DENY; both judge()
implementations return false when unreachable; with no governor the door
opens only on CLAWMATES_DOOR_POLICY=allow. Open Agent Passport (arXiv
2603.20953): 74.6% social-engineering success under a permissive policy,
0 of 879 under a restrictive one. Local override gains the governor prod
already runs.

skill_self_authoring: default flipped to OFF. No agent-authored skill has
ever been delivered to a mission or scored; prod held zero proposals.
Enable with CLAWMATES_SKILL_SELF_AUTHORING=1 once promoted skills go
through the files arm and get a Skill-Use score.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WZb5A2kfVfjpdwSochkuHz
This commit is contained in:
Omar Sobh
2026-09-20 22:07:39 -05:00
co-authored by Claude Opus 5
parent 9b7680a605
commit 76ac3714f1
8 changed files with 157 additions and 45 deletions
+42 -5
View File
@@ -227,20 +227,57 @@ pub async fn apply(
/// Is autonomous skill authoring on?
///
/// Default ON, by operator decision. Stated at boot rather than assumed: this
/// flips a human approval gate that has existed since the feature shipped, and
/// a safety gate that changes state silently is how nobody notices it changed.
/// Default OFF since 2026-09-20, by operator decision. It shipped default ON,
/// and in the months since no agent-authored skill was ever delivered to a
/// mission or scored by the Skill-Use scorer — prod's `level_up_proposals`
/// held zero rows on the day of the flip. An auto-apply loop whose output has
/// never been measured is a supply chain of our own making (the shape Cisco
/// found in OpenClaw's third-party skills), so it waits for a human until
/// `promoted_from_brain` skills go through the `files` delivery arm and get
/// a Trigger/Compliance score like the hand-authored ones. Stated at boot
/// either way: a safety gate that changes state silently is how nobody
/// notices it changed.
pub fn self_authoring_enabled() -> bool {
!matches!(
matches!(
std::env::var("CLAWMATES_SKILL_SELF_AUTHORING")
.unwrap_or_default()
.trim()
.to_ascii_lowercase()
.as_str(),
"0" | "off" | "false"
"1" | "on" | "true"
)
}
#[cfg(test)]
mod self_authoring_flag_tests {
/// Serialised through one env var; each case restores the prior state.
fn with(value: Option<&str>, f: impl FnOnce()) {
let key = "CLAWMATES_SKILL_SELF_AUTHORING";
let prior = std::env::var(key).ok();
match value {
Some(v) => std::env::set_var(key, v),
None => std::env::remove_var(key),
}
f();
match prior {
Some(v) => std::env::set_var(key, v),
None => std::env::remove_var(key),
}
}
/// Off unless switched on. The previous default was the reverse.
#[test]
fn off_by_default_on_by_explicit_opt_in() {
with(None, || assert!(!super::self_authoring_enabled()));
with(Some(""), || assert!(!super::self_authoring_enabled()));
with(Some("0"), || assert!(!super::self_authoring_enabled()));
with(Some("yes"), || assert!(!super::self_authoring_enabled()));
with(Some("1"), || assert!(super::self_authoring_enabled()));
with(Some("on"), || assert!(super::self_authoring_enabled()));
with(Some("TRUE"), || assert!(super::self_authoring_enabled()));
}
}
/// Apply a pending proposal's `skill_candidate` items with no human decision.
///
/// ONLY `skill_candidate`. The other item kinds are deliberately left to the