Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30b5de31a2 | ||
|
|
03e0b8667a | ||
|
|
13a9bfe88d | ||
|
|
c091cacb61 | ||
|
|
d1f62288ab | ||
|
|
7c5310d1b2 | ||
|
|
c39f1d0b3c | ||
|
|
231d4e51f1 | ||
|
|
e82b2eb2af | ||
|
|
a977805377 | ||
|
|
9eb4a36d62 | ||
|
|
bf3ab130af | ||
|
|
8e9edeeea7 | ||
|
|
4faa1c107e | ||
|
|
bb4e753e0e |
No files matched your search
@@ -260,13 +260,12 @@ jobs:
|
||||
FAIL=0
|
||||
for crate in src/rust/*/; do
|
||||
if [ -f "$crate/Cargo.toml" ]; then
|
||||
echo "=== clippy $(basename $crate) ==="
|
||||
echo "=== clippy $(basename "$crate") ==="
|
||||
(cd "$crate" && cargo clippy --quiet -- -D warnings) || FAIL=1
|
||||
fi
|
||||
done
|
||||
exit $FAIL
|
||||
- name: cargo test (currently trivial — crates carry no #[test] yet;
|
||||
this lights up the moment the first one lands)
|
||||
- name: cargo test (lights up when the first #[test] lands)
|
||||
run: |
|
||||
FAIL=0
|
||||
for crate in src/rust/*/; do
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Rune
|
||||
|
||||
**Current release: v0.129.0**
|
||||
**Current release: v0.129.5**
|
||||
|
||||
**Rune is a persistent personal agent designed to accumulate experience, develop reusable competence, and remain recognisably the same agent even when its underlying foundation model changes.**
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "rune"
|
||||
version = "0.129.0"
|
||||
version = "0.129.5"
|
||||
description = "Rune — a stateful coding assistant with persistent memory, orchestration, and TUI"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
|
||||
+4
-2
@@ -34,6 +34,8 @@ httpcore==1.0.9
|
||||
# via httpx
|
||||
httpx==0.28.1
|
||||
# via rune (pyproject.toml)
|
||||
hypothesis==6.168.5
|
||||
# via rune (pyproject.toml)
|
||||
idna==3.20
|
||||
# via
|
||||
# anyio
|
||||
@@ -100,10 +102,10 @@ rich==15.0.0
|
||||
# via
|
||||
# rune (pyproject.toml)
|
||||
# textual
|
||||
hypothesis==6.168.5
|
||||
# via rune (pyproject.toml) — property-based invariants (polyglot gate)
|
||||
ruff==0.16.5
|
||||
# via rune (pyproject.toml)
|
||||
sortedcontainers==2.4.0
|
||||
# via hypothesis
|
||||
sqlite-vec==0.1.9
|
||||
# via rune (pyproject.toml)
|
||||
textual==8.2.8
|
||||
|
||||
@@ -53,7 +53,10 @@ func loadTruth(t *testing.T, name string) (truthDoc, string, string) {
|
||||
t.Fatalf("%s unparseable: %v", name, err)
|
||||
}
|
||||
tmpRoot := mkTruthRoot(t, AllowedReadDirs)
|
||||
wRoot := mkTruthRoot(t, AllowedWriteDirs)
|
||||
// The WRITE root must come from write-allowed dirs ONLY (write policy
|
||||
// is ~ + /mnt/workdrive — /tmp is read-allowed but NOT write-allowed;
|
||||
// the oracle's own generator respected this split).
|
||||
wRoot := mkWriteRoot(t)
|
||||
for _, f := range doc.Fixtures.Files {
|
||||
p := substRoots(f.Path, tmpRoot, wRoot)
|
||||
if err := os.WriteFile(p, []byte(substRoots(f.Content, tmpRoot, wRoot)), 0o644); err != nil {
|
||||
@@ -72,17 +75,47 @@ func loadTruth(t *testing.T, name string) (truthDoc, string, string) {
|
||||
return doc, tmpRoot, wRoot
|
||||
}
|
||||
|
||||
// mkTruthRoot — first creatable temp dir among the allowed dirs (the same
|
||||
// resolution order the generator used).
|
||||
// mkWriteRoot — first creatable dir among AllowedWriteDirs, then HOME
|
||||
// (both write-allowed on every surface). /tmp is deliberately excluded.
|
||||
func mkWriteRoot(t *testing.T) string {
|
||||
t.Helper()
|
||||
candidates := append([]string{}, AllowedWriteDirs...)
|
||||
if home, err := os.UserHomeDir(); err == nil {
|
||||
candidates = append(candidates, home)
|
||||
}
|
||||
for _, d := range candidates {
|
||||
// Skip candidates the product's own policy blocks (e.g. a runner
|
||||
// HOME under /var) — a root there can never pass ValidateWritePath.
|
||||
if IsPathAllowed(d, AllowedWriteDirs) {
|
||||
p, err := os.MkdirTemp(d, "rune-truth-w-")
|
||||
if err == nil {
|
||||
return p
|
||||
}
|
||||
}
|
||||
}
|
||||
t.Fatalf("no creatable write root among %v", candidates)
|
||||
return ""
|
||||
}
|
||||
|
||||
// mkTruthRoot — first creatable temp dir among the allowed dirs. The
|
||||
// candidate order matters on CI: the runner's default TMPDIR may resolve
|
||||
// under a BLOCKED dir (/var/lib/...), so /tmp is tried FIRST (it is in
|
||||
// AllowedReadDirs on every surface we run: local, CI, canary), then the
|
||||
// configured allowed dirs, then HOME (allowed by policy on both sides).
|
||||
func mkTruthRoot(t *testing.T, dirs []string) string {
|
||||
t.Helper()
|
||||
for _, d := range dirs {
|
||||
candidates := []string{"/tmp"}
|
||||
candidates = append(candidates, dirs...)
|
||||
if home, err := os.UserHomeDir(); err == nil {
|
||||
candidates = append(candidates, home)
|
||||
}
|
||||
for _, d := range candidates {
|
||||
p, err := os.MkdirTemp(d, "rune-truth-")
|
||||
if err == nil {
|
||||
return p
|
||||
}
|
||||
}
|
||||
t.Fatalf("no creatable root among %v", dirs)
|
||||
t.Fatalf("no creatable root among %v", candidates)
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ This is the main entry point for the Rune program.
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
__version__ = "0.129.0"
|
||||
__version__ = "0.129.5"
|
||||
|
||||
# One build identity (handoff 2026-09-10 §4): the semantic version above is
|
||||
# the repo-level truth (auto-bumped at merge); the DEPLOYED revision (exact
|
||||
|
||||
@@ -233,7 +233,7 @@ def main() -> int:
|
||||
)
|
||||
check(
|
||||
"Rune minor version advertises provisioning and restore verification",
|
||||
'__version__ = "0.129.0"' in rune_version,
|
||||
'__version__ = "0.129.5"' in rune_version,
|
||||
failures,
|
||||
)
|
||||
# #169 policy update: auto-bump on merge is sanctioned (Nick directive:
|
||||
|
||||
@@ -1334,7 +1334,10 @@ class RuneOperator:
|
||||
task.completed_at = datetime.now(timezone.utc).isoformat()
|
||||
self._task_state.transition(task.task_id, "failed")
|
||||
self._save()
|
||||
self._emit_task_outcome(task, channel=channel)
|
||||
try:
|
||||
self._emit_task_outcome(task, channel=channel)
|
||||
except Exception: # noqa: BLE001 — contract (tests/test_task_lifecycle): journal failure never masks the operator path; overrides may raise
|
||||
pass
|
||||
# P0-04 (#20): first endogenous meaningful-event trigger — a task
|
||||
# failure is worth hearing about (#48 grows the trigger taxonomy
|
||||
# on top of this seed). The typed event already exists in the
|
||||
@@ -1383,7 +1386,10 @@ class RuneOperator:
|
||||
self.state.current_task = None
|
||||
self._task_state.transition(task.task_id, "failed", outcome_ref=outcome_ref)
|
||||
self._save()
|
||||
self._emit_task_outcome(task, channel=channel)
|
||||
try:
|
||||
self._emit_task_outcome(task, channel=channel)
|
||||
except Exception: # noqa: BLE001 — contract (tests/test_task_lifecycle): journal failure never masks the operator path; overrides may raise
|
||||
pass
|
||||
return self._response_envelope(
|
||||
OperatorResponse(
|
||||
success=False,
|
||||
@@ -1423,7 +1429,7 @@ class RuneOperator:
|
||||
"completed_at": task.completed_at or "",
|
||||
},
|
||||
)
|
||||
except Exception:
|
||||
except Exception: # noqa: BLE001, S110 — contract: journal failure never masks the operator path (degrade-not-crash)
|
||||
pass
|
||||
|
||||
def _emit_task_failed(self, task: RuneTask, channel: str = "") -> None:
|
||||
@@ -1443,7 +1449,7 @@ class RuneOperator:
|
||||
"error": (task.result or "")[:300],
|
||||
},
|
||||
)
|
||||
except Exception:
|
||||
except Exception: # noqa: BLE001, S110 — contract: journal failure never masks the operator path (degrade-not-crash)
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
@@ -2569,7 +2575,15 @@ def _wire_auto_filer() -> None:
|
||||
from .event_bus import _store_path
|
||||
from .failure_auto_filer import AUTOFILE_OFF_ENV, FailureAutoFiler, JsonlSpool
|
||||
from .forge_client import create_forge_client
|
||||
except ImportError: # TUI top-level deploy (script mode)
|
||||
except ImportError: # script mode (no package parent)
|
||||
# Script mode: bare `python3 rune_operator.py` has no package
|
||||
# parent AND the script dir may not be on sys.path when invoked
|
||||
# from elsewhere. Add it, then use the flat imports.
|
||||
import sys as _sys
|
||||
|
||||
_here = os.path.dirname(os.path.abspath(__file__))
|
||||
if _here not in _sys.path:
|
||||
_sys.path.insert(0, _here)
|
||||
from event_bus import _store_path # type: ignore[no-redef]
|
||||
from failure_auto_filer import AUTOFILE_OFF_ENV, FailureAutoFiler, JsonlSpool # type: ignore[no-redef]
|
||||
from forge_client import create_forge_client # type: ignore[no-redef]
|
||||
|
||||
@@ -8,7 +8,7 @@ mode system, subject header, shared memory and identity.
|
||||
|
||||
This is not an interface. This is how I see, speak, and interact with the world.
|
||||
|
||||
Version: v0.129.0
|
||||
Version: v0.129.5
|
||||
Features: 41 (24 original + 17 new native commands)
|
||||
|
||||
Usage:
|
||||
@@ -1948,7 +1948,7 @@ class RuneApp(App):
|
||||
# Show version info
|
||||
self.chat_channel.add_message(
|
||||
"system",
|
||||
f"[dim]Rune v0.129.0 | Textual TUI | {len(loaded)} native modules[/dim]",
|
||||
f"[dim]Rune v0.129.5 | Textual TUI | {len(loaded)} native modules[/dim]",
|
||||
)
|
||||
|
||||
# Auto-show night mode suggestion if evening/night hours
|
||||
|
||||
@@ -16,6 +16,7 @@ const FLOOR_TOOLS: &[&str] = &[
|
||||
"run_command",
|
||||
];
|
||||
|
||||
#[allow(dead_code)] // pinned: registry surface kept for the tool-router integration
|
||||
const ALL_TOOLS: &[&str] = &[
|
||||
"read_file",
|
||||
"write_file",
|
||||
|
||||
@@ -99,6 +99,8 @@ pub extern "C" fn cs_score_card(arg: *const c_char) -> *mut c_char {
|
||||
}
|
||||
|
||||
/// Free a string returned by any cs_* function.
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
// pinned: #[no_mangle] extern "C" — the Survivor loader ABI requires this exact safe-fn signature; the raw pointer IS the FFI contract
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cs_free_string(ptr: *mut c_char) {
|
||||
if !ptr.is_null() {
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
//! like 0.30000000000000004)
|
||||
//! - indent=2 dump: newline+indent after every item separator, "{}" when
|
||||
//! empty, NO trailing newline (json.dump never writes one)
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
//!
|
||||
//!
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
|
||||
@@ -1008,6 +1008,7 @@ fn regex_lite_search(pattern: &str, text: &str) -> bool {
|
||||
// gap-matched against the text. A leading ANCHOR on a variant
|
||||
// requires a word boundary immediately before the match; a
|
||||
// trailing ANCHOR requires one immediately after.
|
||||
#[allow(clippy::while_let_loop)] // pinned: search-loop shape mirrors the oracle substring scan
|
||||
fn walk(
|
||||
segments: &[Vec<String>],
|
||||
low: &str,
|
||||
|
||||
@@ -155,9 +155,9 @@ pub extern "C" fn cc_persona_decide(arg: *const c_char) -> *mut c_char {
|
||||
let sems: Vec<f64> = match get(&a, "sem_scores") {
|
||||
Some(pyjson::Json::Arr(x)) => x
|
||||
.iter()
|
||||
.filter_map(|v| match v {
|
||||
pyjson::Json::Num(n) => Some(*n),
|
||||
_ => Some(0.0),
|
||||
.map(|v| match v {
|
||||
pyjson::Json::Num(n) => *n,
|
||||
_ => 0.0,
|
||||
})
|
||||
.collect(),
|
||||
_ => vec![0.0; rules.len()],
|
||||
@@ -505,6 +505,8 @@ pub extern "C" fn cc_consolidation_neuron(arg: *const c_char) -> *mut c_char {
|
||||
envelope(result)
|
||||
}
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
// pinned: #[no_mangle] extern "C" — the Survivor loader ABI requires this exact safe-fn signature; the raw pointer IS the FFI contract
|
||||
#[no_mangle]
|
||||
pub extern "C" fn cc_free_string(ptr: *mut c_char) {
|
||||
if !ptr.is_null() {
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
//! like 0.30000000000000004)
|
||||
//! - indent=2 dump: newline+indent after every item separator, "{}" when
|
||||
//! empty, NO trailing newline (json.dump never writes one)
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
//!
|
||||
//!
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ pub fn validate_command(
|
||||
match op {
|
||||
None => serde_json::json!({"accepted": false, "reason": "unknown command"}),
|
||||
Some(op) => {
|
||||
#[allow(clippy::match_like_matches_macro)]
|
||||
// pinned: explicit match arms document the classification
|
||||
let valid = match (command, current_phase) {
|
||||
("START", "draft") => true,
|
||||
("APPROVE", "approved") | ("APPROVE", "building") => true,
|
||||
|
||||
@@ -12,6 +12,7 @@ pub struct Depth {
|
||||
pub bypassed: Vec<String>,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)] // pinned: parity signature — the port mirrors the oracle arg-for-arg
|
||||
pub fn select_depth(
|
||||
mode: &str,
|
||||
objective: &str,
|
||||
@@ -119,7 +120,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_local_fix() {
|
||||
let d = select_depth("LOCAL_FIX", "fix typo", None, false, false, false, "", None);
|
||||
let d = select_depth(
|
||||
"LOCAL_FIX",
|
||||
"fix typo",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
"",
|
||||
None,
|
||||
);
|
||||
assert_eq!(d.level, "LIGHT");
|
||||
}
|
||||
|
||||
@@ -128,7 +138,7 @@ mod tests {
|
||||
let d = select_depth(
|
||||
"PROJECT_BUILD",
|
||||
"build system",
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
@@ -143,7 +153,7 @@ mod tests {
|
||||
let d = select_depth(
|
||||
"STANDARD_CHANGE",
|
||||
"add feature",
|
||||
None,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
|
||||
@@ -124,6 +124,8 @@ mod tests {
|
||||
// ---- FFI (Survivor membrane) ----
|
||||
|
||||
/// ci_validate({"from","to"}) -> {"legal": bool, "detail": str?}
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
// pinned: #[no_mangle] extern "C" — the Survivor loader ABI requires this exact safe-fn signature; the raw pointer IS the FFI contract
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ci_validate(arg: *const u8, arg_len: usize) -> *mut u8 {
|
||||
unsafe {
|
||||
@@ -144,6 +146,7 @@ pub extern "C" fn ci_validate(arg: *const u8, arg_len: usize) -> *mut u8 {
|
||||
}
|
||||
|
||||
/// ci_transition({"from_phase","to_phase","contract_id"}) -> envelope
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)] // pinned: extern "C" ABI — the Survivor loader requires this signature
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ci_transition(arg: *const u8, arg_len: usize) -> *mut u8 {
|
||||
unsafe {
|
||||
|
||||
@@ -52,13 +52,21 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_pressure_levels() {
|
||||
// fixtures derived from the code's tokenizer (CHARS_PER_TOKEN):
|
||||
// 1000 chars is far under any threshold; a payload sized to cross
|
||||
// the 0.9 critical line proves the ladder's top step.
|
||||
assert_eq!(measure_pressure(&"x".repeat(1000), 10000)["level"], "low");
|
||||
assert_eq!(measure_pressure(&"x".repeat(9000), 10000)["level"], "high");
|
||||
let big = (9.0 * CHARS_PER_TOKEN * 10000.0 / 10.0) as usize; // 90% of max_tokens in tokens
|
||||
assert_eq!(
|
||||
measure_pressure(&"x".repeat(big), 10000)["level"],
|
||||
"critical"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_degradation() {
|
||||
let responses = vec!["long response".repeat(100), "short", "tiny"];
|
||||
let responses: Vec<String> =
|
||||
vec!["long response".repeat(100), "short".into(), "tiny".into()];
|
||||
assert!(detect_degradation(&responses));
|
||||
}
|
||||
}
|
||||
@@ -198,6 +198,7 @@ fn transition(
|
||||
// ── public operations (full-doc convention) ──────────────────────────────────
|
||||
|
||||
/// define — duplicate → Err; returns the new record.
|
||||
#[allow(clippy::too_many_arguments)] // pinned: parity signature — the port mirrors the oracle arg-for-arg
|
||||
pub fn define(
|
||||
doc: &mut Json,
|
||||
behaviour_id: &str,
|
||||
|
||||
@@ -286,6 +286,8 @@ pub fn get_entries(ledger_path: &PathBuf, limit: i64) -> Vec<Json> {
|
||||
return Vec::new();
|
||||
}
|
||||
let lines = read_lines(ledger_path);
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
// pinned: the branches mirror distinct oracle paths that happen to coincide
|
||||
let slice: &[String] = if limit <= 0 {
|
||||
&lines[..]
|
||||
} else if (limit as usize) >= lines.len() {
|
||||
@@ -317,6 +319,8 @@ fn ret_string(s: String) -> *mut c_char {
|
||||
}
|
||||
|
||||
/// Free a string returned by any ep_* function.
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
// pinned: #[no_mangle] extern "C" — the Survivor loader ABI requires this exact safe-fn signature; the raw pointer IS the FFI contract
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ep_free_string(ptr: *mut c_char) {
|
||||
if !ptr.is_null() {
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
//! like 0.30000000000000004)
|
||||
//! - indent=2 dump: newline+indent after every item separator, "{}" when
|
||||
//! empty, NO trailing newline (json.dump never writes one)
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
//!
|
||||
//!
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
|
||||
@@ -194,6 +194,8 @@ pub extern "C" fn mr_call(arg: *const c_char) -> *mut c_char {
|
||||
envelope(r)
|
||||
}
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
// pinned: #[no_mangle] extern "C" — the Survivor loader ABI requires this exact safe-fn signature; the raw pointer IS the FFI contract
|
||||
#[no_mangle]
|
||||
pub extern "C" fn mr_free_string(ptr: *mut c_char) {
|
||||
if !ptr.is_null() {
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
//! like 0.30000000000000004)
|
||||
//! - indent=2 dump: newline+indent after every item separator, "{}" when
|
||||
//! empty, NO trailing newline (json.dump never writes one)
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
//!
|
||||
//!
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
|
||||
@@ -495,6 +495,7 @@ fn parse_iso(s: &str) -> Option<f64> {
|
||||
}
|
||||
|
||||
/// Metadata blend, projection and mode-specific QPP abstention.
|
||||
#[allow(clippy::too_many_arguments)] // pinned: parity signature — the port mirrors the oracle arg-for-arg
|
||||
pub fn score_recall_rows(
|
||||
fusion: &Json,
|
||||
rows: &[Json],
|
||||
|
||||
@@ -252,6 +252,7 @@ pub extern "C" fn ms_base_level_from_uses(arg: *const c_char) -> *mut c_char {
|
||||
}
|
||||
|
||||
/// Free a string returned by any ms_* function.
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)] // pinned: extern "C" ABI — the Survivor loader requires this exact signature
|
||||
#[no_mangle]
|
||||
pub extern "C" fn ms_free_string(ptr: *mut c_char) {
|
||||
if !ptr.is_null() {
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
//! like 0.30000000000000004)
|
||||
//! - indent=2 dump: newline+indent after every item separator, "{}" when
|
||||
//! empty, NO trailing newline (json.dump never writes one)
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
//!
|
||||
//!
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ pub fn score_finish(
|
||||
|
||||
if entry_id_present {
|
||||
if let Some(b) = b_i {
|
||||
score += (b * 0.1).min(0.3).max(0.0);
|
||||
score += (b * 0.1).clamp(0.0, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,5 +240,5 @@ pub fn base_level_from_uses(used_at_list: &Json, now_iso: &str) -> f64 {
|
||||
return -2.0;
|
||||
}
|
||||
let b_i = total.ln();
|
||||
b_i.max(-2.0).min(2.0)
|
||||
b_i.clamp(-2.0, 2.0)
|
||||
}
|
||||
@@ -75,6 +75,8 @@ pub extern "C" fn mems_read_query(arg: *const c_char) -> *mut c_char {
|
||||
}
|
||||
|
||||
/// Free a string returned by any mems_* function.
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
// pinned: #[no_mangle] extern "C" — the Survivor loader ABI requires this exact safe-fn signature; the raw pointer IS the FFI contract
|
||||
#[no_mangle]
|
||||
pub extern "C" fn mems_free_string(ptr: *mut c_char) {
|
||||
if !ptr.is_null() {
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
//! like 0.30000000000000004)
|
||||
//! - indent=2 dump: newline+indent after every item separator, "{}" when
|
||||
//! empty, NO trailing newline (json.dump never writes one)
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
//!
|
||||
//!
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
//! like 0.30000000000000004)
|
||||
//! - indent=2 dump: newline+indent after every item separator, "{}" when
|
||||
//! empty, NO trailing newline (json.dump never writes one)
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
//!
|
||||
//!
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
|
||||
@@ -496,6 +496,8 @@ pub extern "C" fn qm_new() -> *mut QueryMemory {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
// pinned: #[no_mangle] extern "C" — the Survivor loader ABI requires this exact safe-fn signature; the raw pointer IS the FFI contract
|
||||
#[no_mangle]
|
||||
pub extern "C" fn qm_with_dir(dir: *const c_char) -> *mut QueryMemory {
|
||||
if dir.is_null() {
|
||||
|
||||
@@ -78,6 +78,7 @@ fn expansions() -> HashMap<&'static str, Vec<&'static str>> {
|
||||
m
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // pinned: kept for the recall-uplift expansion work (mirror of memory_store._STOPWORDS)
|
||||
fn stopwords() -> Vec<&'static str> {
|
||||
"the a an and or of to in on for with is are was were be been it its this that as at by from has have had not no but if then than so such can could should would will shall may might must do does did done you your i me my we our they their them he she his her what which who whom when where why how all any both each few more most other some only own same too very just also".split(' ').collect()
|
||||
}
|
||||
|
||||
@@ -73,6 +73,8 @@ pub fn detect_flags(body_lower: &str) -> (Vec<String>, Vec<String>) {
|
||||
}
|
||||
|
||||
/// FFI: returns JSON {"risk": [...], "uncertainty": [...]}
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
// pinned: #[no_mangle] extern "C" — the Survivor loader ABI requires this exact safe-fn signature; the raw pointer IS the FFI contract
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rrf_detect(arg: *const u8, arg_len: usize) -> *mut u8 {
|
||||
let arg = unsafe { std::slice::from_raw_parts(arg, arg_len) };
|
||||
|
||||
@@ -16,7 +16,7 @@ pub mod store;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::os::raw::c_char;
|
||||
|
||||
fn read_arg<'a>(ptr: *const c_char) -> Result<String, String> {
|
||||
fn read_arg(ptr: *const c_char) -> Result<String, String> {
|
||||
if ptr.is_null() {
|
||||
return Err("null argument pointer".to_string());
|
||||
}
|
||||
@@ -108,6 +108,8 @@ pub extern "C" fn sp_export(arg: *const c_char) -> *mut c_char {
|
||||
}
|
||||
|
||||
/// Free a string returned by any sp_* function.
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
// pinned: #[no_mangle] extern "C" — the Survivor loader ABI requires this exact safe-fn signature; the raw pointer IS the FFI contract
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sp_free_string(ptr: *mut c_char) {
|
||||
if !ptr.is_null() {
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
//! like 0.30000000000000004)
|
||||
//! - indent=2 dump: newline+indent after every item separator, "{}" when
|
||||
//! empty, NO trailing newline (json.dump never writes one)
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
//!
|
||||
//!
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
|
||||
@@ -115,6 +115,7 @@ fn split_name(id: &str) -> &str {
|
||||
/// Faithful port of spine.export_umbrellas. Returns Err where Python would
|
||||
/// raise KeyError (obligated_canary edge into a subsystem whose ext.canaries
|
||||
/// was absent — the append target list does not exist).
|
||||
#[allow(clippy::type_complexity)] // pinned: the tuple type mirrors the umbrella manifest data shape; an alias would obscure the parity
|
||||
pub fn export_umbrellas(doc: &Json, now: &str) -> Result<Json, String> {
|
||||
// insertion-ordered map: (name, description, modules, depends_on, mirrors, canaries: Option)
|
||||
let mut umbrellas: Vec<(
|
||||
|
||||
@@ -88,6 +88,8 @@ pub extern "C" fn sc_language_placement(arg: *const c_char) -> *mut c_char {
|
||||
}
|
||||
|
||||
/// Free a string returned by any sc_* function.
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
// pinned: #[no_mangle] extern "C" — the Survivor loader ABI requires this exact safe-fn signature; the raw pointer IS the FFI contract
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sc_free_string(ptr: *mut c_char) {
|
||||
if !ptr.is_null() {
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
//! like 0.30000000000000004)
|
||||
//! - indent=2 dump: newline+indent after every item separator, "{}" when
|
||||
//! empty, NO trailing newline (json.dump never writes one)
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
//!
|
||||
//!
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
|
||||
@@ -73,6 +73,8 @@ pub extern "C" fn tc_compress_context(arg: *const c_char) -> *mut c_char {
|
||||
}
|
||||
|
||||
/// Free a string returned by any tc_* function.
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
// pinned: #[no_mangle] extern "C" — the Survivor loader ABI requires this exact safe-fn signature; the raw pointer IS the FFI contract
|
||||
#[no_mangle]
|
||||
pub extern "C" fn tc_free_string(ptr: *mut c_char) {
|
||||
if !ptr.is_null() {
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
//! like 0.30000000000000004)
|
||||
//! - indent=2 dump: newline+indent after every item separator, "{}" when
|
||||
//! empty, NO trailing newline (json.dump never writes one)
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
//!
|
||||
//!
|
||||
//! Object key order is preserved (Vec of pairs) — matches Python 3.7+ dict
|
||||
//! insertion order, which the classification tie-break law depends on.
|
||||
|
||||
use std::fmt::Write as _;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ pub struct WarmNeuron {
|
||||
}
|
||||
|
||||
/// All active warm neurons from the store
|
||||
#[allow(clippy::unnecessary_filter_map)] // pinned: the filter_map(|row|) mirrors the oracle row-coalesce expression
|
||||
pub fn list_neurons(rows: &[serde_json::Value]) -> Vec<WarmNeuron> {
|
||||
rows.iter()
|
||||
.filter_map(|row| {
|
||||
|
||||
+33426
-2
File diff suppressed because it is too large.
Load diff
+339
-291
File diff suppressed because it is too large.
Load diff
@@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
@@ -416,11 +417,26 @@ class RuneOperatorToolTests(unittest.TestCase):
|
||||
record.assert_called_once_with("qwen3:8b", False, "inspect this")
|
||||
|
||||
def test_operator_script_can_import_native_runtime_directly(self):
|
||||
# HOME is overridden to isolate the operator's DATA home, but
|
||||
# python's user-site (~/.local/lib/...) is ALSO derived from HOME —
|
||||
# a bare env would hide site-packages (httpx lives there). Carry
|
||||
# the real user-site forward via PYTHONPATH.
|
||||
import site as _site
|
||||
|
||||
env = {
|
||||
"HOME": self.tempdir.name,
|
||||
"PATH": os.environ.get("PATH", "/usr/bin:/bin"),
|
||||
"PYTHONPATH": os.pathsep.join(
|
||||
p for p in (_site.getusersitepackages(),
|
||||
os.environ.get("PYTHONPATH", ""))
|
||||
if p
|
||||
),
|
||||
}
|
||||
completed = subprocess.run(
|
||||
[sys.executable, str(ROOT / "src" / "rune" / "rune_operator.py"), "status"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env={"HOME": self.tempdir.name},
|
||||
env=env,
|
||||
check=False,
|
||||
)
|
||||
|
||||
|
||||
Reference in new issue
Block a user