Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -646,15 +646,14 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
# `build.warnings` (repo-wide .cargo/config.toml) denies ALL local-package rustdoc
# warnings, not just `rustdoc::broken_intra_doc_links` — it independently catches
# `rustdoc::private_intra_doc_links` and `rustdoc::redundant_explicit_links` too, which
# this job's own RUSTDOCFLAGS never enforced. Pre-existing (unrelated to any single PR)
# instances of those two lints exist workspace-wide; overriding to "allow" here keeps
# this job's enforcement scoped to exactly what RUSTDOCFLAGS denies, unchanged from
# before this migration (#5873) — fixing the pre-existing instances is a separate,
# larger doc-cleanup effort, not in scope for a CI-gate-mechanism migration.
# warnings, not just what RUSTDOCFLAGS explicitly denies below — overriding to "allow"
# here keeps this job's enforcement scoped to exactly the three lints RUSTDOCFLAGS names,
# unchanged from before this migration (#5873). `rustdoc::private_intra_doc_links` and
# `rustdoc::redundant_explicit_links` are denied explicitly (not just left to
# `build.warnings`, which this env var disables) so the 39-site cleanup from #5894 has a
# forward regression guardrail in both CI and local dev, not just a one-time sweep.
env:
RUSTDOCFLAGS: "--deny rustdoc::broken_intra_doc_links"
RUSTDOCFLAGS: "--deny rustdoc::broken_intra_doc_links --deny rustdoc::private_intra_doc_links --deny rustdoc::redundant_explicit_links"
CARGO_BUILD_WARNINGS: "allow"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

### Fixed

- `fix`: allowed the `linker_messages` rustc lint via `[workspace.lints.rust]` so plain
`cargo build`/`cargo run` succeeds on macOS/arm64, where Apple's `ld` linker warns on binaries
whose `__eh_frame` section exceeds 16MB and `build.warnings = "deny"` (#5891) denies that
warning unconditionally (#5895). Fixed 39 pre-existing rustdoc `private_intra_doc_links` /
`redundant_explicit_links` warnings across 11 crates surfaced by the same `build.warnings`
migration, and tightened `.github/workflows/ci.yml`'s `rustdoc` job `RUSTDOCFLAGS` to deny
both lint classes explicitly (previously only `rustdoc::broken_intra_doc_links` was denied,
relying on `build.warnings` for the other two — which the job's own `CARGO_BUILD_WARNINGS:
allow` override disabled) so the cleanup has a standing regression guardrail instead of a
one-time sweep (#5894).
- `fix(llm)`: swept superseded Claude model IDs (`claude-sonnet-4-6`, `claude-opus-4-6`) to the
current recommended defaults (`claude-sonnet-5`, `claude-opus-4-8`) across docs, config
examples, source comments, and test fixtures. `ClaudeProvider::new()`'s staleness warning
Expand Down
17 changes: 17 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,23 @@ zeroize = { version = "1.9.0", default-features = false }

[workspace.lints.rust]
unsafe_code = "deny"
# Apple's `ld` linker on macOS/arm64 warns when a binary's `__eh_frame` section
# exceeds 16MB (compact-unwind-table format limit) — a platform-specific linker
# artifact of the `zeph` binary's size, not a code defect. `build.warnings = "deny"`
# (.cargo/config.toml, #5891) denies this via `#[warn(linker_messages)]` like any
# other lint, unconditionally failing `cargo build --features full` on macOS/arm64.
# `build.warnings` has no category-granular equivalent (verified against the Cargo
# 1.97 reference: it is a plain string, not a table) so the lint is allowed here
# instead. Note `linker_messages` is a single all-or-nothing rustc lint over every
# warning the linker writes to stderr, not just this eh_frame case — there is no
# per-message granularity, so this allow is workspace-wide (via each crate's
# existing `[lints] workspace = true` inheritance) and applies on every platform,
# including CI's Linux runners, where it is a no-op today only because Linux's
# linker never emits the eh_frame warning specifically, not because the lint is
# scoped to it. Accepted tradeoff: linker *errors* still fail the build; only
# non-fatal linker diagnostics are suppressed. All other rustc/clippy/rustdoc
# warnings remain denied. See #5895.
linker_messages = "allow"

[workspace.lints.clippy]
all = "warn"
Expand Down
4 changes: 2 additions & 2 deletions crates/zeph-acp/src/transport/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//! present in direct byte comparison.
//!
//! Supports multiple named clients (#5868): each configured
//! [`AcpClientToken`](crate::transport::AcpClientToken) authenticates its own token, and on
//! [`AcpClientToken`] authenticates its own token, and on
//! match the matched client's `id` is injected as [`TokenIdentity`] into the request's
//! extensions — downstream handlers read it to derive the connection's `owner_key` for ACP
//! session-persistence scoping.
Expand All @@ -24,7 +24,7 @@ use tower::{Layer, Service};

use crate::transport::AcpClientToken;

/// Authenticated client identity, injected into request extensions by [`BearerAuthLayer`] on
/// Authenticated client identity, injected into request extensions by `BearerAuthLayer` on
/// a successful bearer-token match. Absent when no auth layer is applied (empty client list).
///
/// `pub` (not `pub(crate)`) solely so it can appear as an `axum` extractor parameter type on
Expand Down
2 changes: 1 addition & 1 deletion crates/zeph-acp/src/transport/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ pub async fn serve_stdio(
/// on a dedicated thread with a `current_thread` runtime and `LocalSet`.
///
/// `owner_key` (#5868) scopes this connection's persisted session list/load/resume — see
/// [`build_agent_state`].
/// `build_agent_state`.
///
/// # Errors
///
Expand Down
6 changes: 3 additions & 3 deletions crates/zeph-bench/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use crate::scenario::{DatasetLoader, Evaluator, Scenario};

/// Controls how the runner processes the agent's raw text response.
///
/// Used by [`BenchRunner::run_one_with_executor`] to select the appropriate
/// Used by `BenchRunner::run_one_with_executor` to select the appropriate
/// system prompt and post-processing behaviour.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
Expand Down Expand Up @@ -86,7 +86,7 @@ pub enum MemoryMode {
/// Parameters required to construct a per-scenario `SQLite`-backed `SemanticMemory`.
///
/// Populated by [`BenchRunner::with_memory_params`] and consumed inside
/// [`BenchRunner::run_one`] when `opts.memory_mode == MemoryMode::On`.
/// `BenchRunner::run_one` when `opts.memory_mode == MemoryMode::On`.
///
/// # Examples
///
Expand Down Expand Up @@ -204,7 +204,7 @@ impl BenchRunner {
/// Attach `SemanticMemory` parameters for memory-on benchmark runs.
///
/// When set, a per-scenario `SQLite`-backed `SemanticMemory` is constructed inside
/// [`run_one`][BenchRunner::run_one] whenever `opts.memory_mode == MemoryMode::On`.
/// `run_one` whenever `opts.memory_mode == MemoryMode::On`.
///
/// # Examples
///
Expand Down
2 changes: 1 addition & 1 deletion crates/zeph-channels/src/telegram_api_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ impl TelegramApiClient {
/// `post()` call appends only the method name (e.g., `/answerGuestQuery`).
///
/// Creates an independent `reqwest::Client` with its own connection pool and
/// a [`REQUEST_TIMEOUT`] per-request timeout. To share a connection pool with
/// a `REQUEST_TIMEOUT` per-request timeout. To share a connection pool with
/// an existing client, use [`TelegramApiClient::with_client`].
///
/// # Panics
Expand Down
4 changes: 2 additions & 2 deletions crates/zeph-core/src/agent/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ impl<C: Channel> Agent<C> {
///
/// # Errors
///
/// Returns [`BuildError::MissingProviders`] when no provider pool was configured and the
/// Returns `BuildError::MissingProviders` when no provider pool was configured and the
/// model name has not been set via `apply_session_config` (the agent cannot make LLM calls).
///
/// # Examples
Expand Down Expand Up @@ -2184,7 +2184,7 @@ impl<C: Channel> Agent<C> {
/// Stash the P1 (agent-turn) durable adapter's config/db-url/cipher cheaply — no I/O runs
/// here (#5452). Call only when `config.durable.enabled && config.durable.agent_turns`;
/// the actual `DurableContext` is opened lazily by
/// [`Agent::ensure_session_durable_ctx`](crate::agent::Agent::ensure_session_durable_ctx) on
/// `Agent::ensure_session_durable_ctx` on
/// the first durable-gated call, once the real `TaskSupervisor` is attached
/// (see [`Self::with_task_supervisor`]).
///
Expand Down
6 changes: 3 additions & 3 deletions crates/zeph-core/src/notifications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub enum TurnExitStatus {
/// Lightweight summary of a completed agent turn used as notification input.
///
/// Built by the agent loop after `channel.flush_chunks()` and passed to
/// [`Notifier::fire`]. Contains only what is needed for gate decisions and
/// `Notifier::fire`. Contains only what is needed for gate decisions and
/// notification body assembly — no LLM payloads or raw tool outputs.
#[derive(Debug, Clone)]
pub struct TurnSummary {
Expand All @@ -88,9 +88,9 @@ pub struct TurnSummary {
/// Per-turn completion notifier.
///
/// Holds a shared [`reqwest::Client`] and the resolved config. Construct once at
/// agent startup via [`Notifier::new`] and call [`Notifier::fire`] after each turn.
/// agent startup via [`Notifier::new`] and call `Notifier::fire` after each turn.
///
/// All I/O is routed through the agent's [`BackgroundSupervisor`] so it is
/// All I/O is routed through the agent's `BackgroundSupervisor` so it is
/// visible in TUI status and bounded by the Telemetry class concurrency limit.
/// `fire` returns immediately without blocking the agent loop.
///
Expand Down
2 changes: 1 addition & 1 deletion crates/zeph-core/src/serve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl SessionActor {
/// [`TaskSupervisor::spawn_oneshot`] — visible through `supervisor.snapshot()`. The
/// coordinator never touches the `!Send` `Agent`; it only awaits the dedicated thread's
/// completion signal and, if the supervisor's own `CancellationToken` fires first (process
/// shutdown), forwards cancellation onto the session's own token so [`Self::drive`] observes
/// shutdown), forwards cancellation onto the session's own token so `Self::drive` observes
/// exactly one cancellation source regardless of trigger. Session actors intentionally do not
/// auto-restart on panic or unexpected exit (`spawn_oneshot`'s `RestartPolicy::RunOnce`):
/// re-driving a torn turn or replay in place is unsafe. Recovery is a fresh spawn (re-attach)
Expand Down
2 changes: 1 addition & 1 deletion crates/zeph-durable/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ pub struct ExecutionSummary {
/// Returned by [`LocalBackend::read_execution_redacted`]. It deliberately excludes the payload bytes
/// and full idempotency key — only the metadata the spec's INV-5 redaction rule permits in default
/// output. To see decrypted payloads a caller must opt in via `--reveal`, which reads through the
/// AEAD cipher with [`Journal::read_execution`](crate::Journal::read_execution) instead.
/// AEAD cipher with [`Journal::read_execution`] instead.
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
pub struct RedactedEntry {
/// Global append sequence.
Expand Down
2 changes: 1 addition & 1 deletion crates/zeph-durable/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
//! `max_payload` guard. The concrete cipher lives in a consuming crate (INV-1).
//! - [`effect`] — the [`EffectClass`] side-effect contract referenced by journal entries.
//! - [`config`] — re-exports the pure-data [`DurableConfig`] and [`RetentionPolicy`] (which live in
//! `zeph-config`) and owns the [`encryption_gate`](crate::encryption_gate) AEAD enforcement policy.
//! `zeph-config`) and owns the [`encryption_gate`] AEAD enforcement policy.
//! - [`error`] — the crate-wide [`DurableError`].
//!
//! Persistence engine:
Expand Down
10 changes: 5 additions & 5 deletions crates/zeph-memory/src/graph/store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl GraphStore {
/// Control whether imported (non-conversation) edges appear in recall (spec-067 FR-003).
///
/// When `false`, edges with any non-conversation origin (e.g. `'ingest'`, `'subagent'`)
/// are excluded from [`Self::query_batch_edges`] and [`Self::edges_for_entity`].
/// are excluded from `Self::query_batch_edges` and [`Self::edges_for_entity`].
/// Default: `true` (all edges included).
#[must_use]
pub fn with_recall_include_imported(mut self, include: bool) -> Self {
Expand Down Expand Up @@ -684,7 +684,7 @@ impl GraphStore {
///
/// `SQLite` limits the number of bind parameters to `SQLITE_MAX_VARIABLE_NUMBER` (999 by
/// default). Each entity ID requires two bind slots (source OR target), so batches are
/// chunked at [`SQLITE_BATCH_LIMIT_2X`] to stay safely under the limit regardless of
/// chunked at `SQLITE_BATCH_LIMIT_2X` to stay safely under the limit regardless of
/// compile-time `SQLite` configuration.
///
/// # Errors
Expand Down Expand Up @@ -1389,7 +1389,7 @@ impl GraphStore {
/// Increment `retrieval_count` and set `last_retrieved_at` for a batch of edge IDs.
///
/// Fire-and-forget: errors are logged but not propagated. Caller should log the warning.
/// Batched with [`SQLITE_BATCH_LIMIT_2X`] to stay safely under `SQLite` bind variable limit.
/// Batched with `SQLITE_BATCH_LIMIT_2X` to stay safely under `SQLite` bind variable limit.
/// Each chunk's write is bounded by a 500ms timeout (matching
/// [`Self::qdrant_point_ids_for_entities`]) so a stuck pool surfaces as a typed
/// [`MemoryError::Timeout`] instead of hanging the `graph_recall_astar` hot path.
Expand Down Expand Up @@ -1425,7 +1425,7 @@ impl GraphStore {

/// Increment `weight` on the set of edges traversed during the current recall (HL-F2, #3344).
///
/// Mirrors [`Self::record_edge_retrieval`] in shape: same [`SQLITE_BATCH_LIMIT_2X`] chunking,
/// Mirrors [`Self::record_edge_retrieval`] in shape: same `SQLITE_BATCH_LIMIT_2X` chunking,
/// same `WHERE id IN (…) AND valid_to IS NULL` filter (defensive — traversed edges should
/// already be active, but this prevents reinforcing tombstoned edges).
///
Expand Down Expand Up @@ -1480,7 +1480,7 @@ impl GraphStore {
/// Return the subset of `ids` that exist in `graph_entities`.
///
/// Useful for cross-referencing Qdrant-side entity IDs against the `SQLite` truth.
/// Processes in chunks of [`SQLITE_BATCH_LIMIT_2X`] to stay under the `SQLite` variable
/// Processes in chunks of `SQLITE_BATCH_LIMIT_2X` to stay under the `SQLite` variable
/// limit (~32 k).
///
/// # Errors
Expand Down
2 changes: 1 addition & 1 deletion crates/zeph-memory/src/qdrant_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ impl QdrantOps {
/// # Warning
///
/// Calls made directly through the returned client bypass the [`Self::with_timeout`]
/// guard (#5484) — they are not wrapped by [`Self::timed`]. Prefer the inherent
/// guard (#5484) — they are not wrapped by `Self::timed`. Prefer the inherent
/// `QdrantOps` methods, which are all timeout-guarded, unless the client exposes an
/// operation this type does not wrap.
#[must_use]
Expand Down
2 changes: 1 addition & 1 deletion crates/zeph-memory/src/reasoning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ impl ReasoningMemory {
/// Increment `use_count` and update `last_used_at` for each id in the list.
///
/// Safe to call with an empty slice — no SQL is issued.
/// The list is chunked into batches of [`MAX_IDS_PER_QUERY`] to respect `SQLite`'s
/// The list is chunked into batches of `MAX_IDS_PER_QUERY` to respect `SQLite`'s
/// variable limit.
///
/// # Errors
Expand Down
4 changes: 2 additions & 2 deletions crates/zeph-sanitizer/src/shadow_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const GOAL_SUMMARY_MAX_CHARS: usize = 100;
/// Events are appended to [`ShadowMemory`] in monotonic turn order. The fields capture
/// the most goal-relevant signals without requiring an additional LLM call.
///
/// `goal_summary` is truncated to [`GOAL_SUMMARY_MAX_CHARS`] on ingestion by
/// `goal_summary` is truncated to `GOAL_SUMMARY_MAX_CHARS` on ingestion by
/// [`ShadowMemory::record`], so callers do not need to truncate themselves.
#[derive(Clone)]
pub struct ShadowEvent {
Expand All @@ -64,7 +64,7 @@ pub struct ShadowEvent {
///
/// 0.0 when causal IPI is disabled or probes failed.
pub deviation_score: f32,
/// First [`GOAL_SUMMARY_MAX_CHARS`] characters of the pre-probe response.
/// First `GOAL_SUMMARY_MAX_CHARS` characters of the pre-probe response.
///
/// Empty string when no pre-probe was available (causal IPI disabled).
/// An empty `goal_summary` triggers maximum Jaccard drift penalty.
Expand Down
4 changes: 2 additions & 2 deletions crates/zeph-skills/src/evolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ pub fn build_evaluation_prompt(
/// within the domain of the original skill.
///
/// Placeholders: `{description}`, `{name}`, `{body}` — substituted via
/// [`build_domain_gate_prompt`] using [`render`] (`str::replace` per key, not `format!()`).
/// [`build_domain_gate_prompt`] using `render` (`str::replace` per key, not `format!()`).
///
/// The JSON example in the template (`{"domain_relevant": bool, "reasoning": string}`) uses
/// literal curly braces, which is safe here: `render` only replaces the exact substrings
Expand Down Expand Up @@ -370,7 +370,7 @@ pub struct DomainGateResult {

/// Build a domain gate prompt by substituting template placeholders.
///
/// Uses [`render`] (per-key `str::replace`) rather than `format!()` to avoid interpreting the
/// Uses `render` (per-key `str::replace`) rather than `format!()` to avoid interpreting the
/// JSON example braces in the template as format arguments.
#[must_use]
pub fn build_domain_gate_prompt(name: &str, description: &str, body: &str) -> String {
Expand Down
2 changes: 1 addition & 1 deletion crates/zeph-skills/src/qdrant_matcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl QdrantSkillMatcher {
///
/// Does **not** populate the vector cache read by [`Self::skill_embedding`] — callers that
/// need per-skill vectors (RL rerank, `GoSkills` grouping) must call
/// [`Self::refresh_vector_cache`] explicitly with the final candidate set once it's known
/// `Self::refresh_vector_cache` explicitly with the final candidate set once it's known
/// (e.g. after BM25 hybrid-search fusion), so the extra `get_points` round-trip is only
/// paid when one of those features is actually enabled.
#[cfg_attr(
Expand Down
4 changes: 2 additions & 2 deletions crates/zeph-skills/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
//! cannot be resolved at all (e.g. dangling) is logged at `DEBUG`, since a broken link
//! is not itself a security signal.
//!
//! Traversal is limited to [`MAX_SKILL_DEPTH`] levels to prevent runaway recursion on
//! Traversal is limited to `MAX_SKILL_DEPTH` levels to prevent runaway recursion on
//! adversarial directory trees. A directory at exactly that depth is still descended into;
//! skills deeper than `MAX_SKILL_DEPTH` relative to the base are silently skipped (the
//! limit should be set generously enough that this is never a surprise in practice).
Expand Down Expand Up @@ -154,7 +154,7 @@ impl SkillRegistry {

/// Scan directories recursively for `SKILL.md` files and load metadata only (lazy body).
///
/// Searches at any depth up to [`MAX_SKILL_DEPTH`] using a depth-first pre-order walk
/// Searches at any depth up to `MAX_SKILL_DEPTH` using a depth-first pre-order walk
/// with siblings sorted lexicographically. Earlier paths have higher priority: if a skill
/// with the same name appears in multiple paths or multiple depths within the same path,
/// only the first one encountered in DFS order is kept.
Expand Down
2 changes: 1 addition & 1 deletion crates/zeph-skills/src/semantic_scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl SkillSemanticScanner {
/// `skill_name` and `declared_purpose` are trusted metadata from the plugin manifest.
/// `skill_md_content` is the raw SKILL.md body — untrusted, attacker-controlled.
///
/// Content longer than [`MAX_SCAN_BYTES`] is sampled (head + tail) rather than silently
/// Content longer than `MAX_SCAN_BYTES` is sampled (head + tail) rather than silently
/// truncated; the returned verdict includes a size warning in that case.
///
/// # Errors
Expand Down
4 changes: 2 additions & 2 deletions crates/zeph-tools/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const MAX_CACHE_ENTRIES: usize = 512;
/// - `ttl = None` means entries never expire (useful for batch/scripted sessions).
/// - `ttl = Some(d)` means entries expire after duration `d`.
/// - Lazy eviction: expired entries are removed on `get()`.
/// - LRU eviction: when the entry count reaches [`MAX_CACHE_ENTRIES`], the least-recently-inserted
/// - LRU eviction: when the entry count reaches `MAX_CACHE_ENTRIES`, the least-recently-inserted
/// entry is evicted to bound memory growth in long sessions.
/// - Not `Send + Sync` by design — accessed only from the agent's single-threaded loop.
#[derive(Debug)]
Expand Down Expand Up @@ -137,7 +137,7 @@ impl ToolResultCache {

/// Store a tool result in the cache.
///
/// When the cache is at capacity ([`MAX_CACHE_ENTRIES`]), the oldest entry is evicted
/// When the cache is at capacity (`MAX_CACHE_ENTRIES`), the oldest entry is evicted
/// before inserting the new one to prevent unbounded memory growth in long sessions.
pub fn put(&mut self, key: CacheKey, output: ToolOutput) {
if !self.enabled {
Expand Down
Loading
Loading