Skip to content

Add the self_hosted decision provider (contract 2.9) - #69

Open
UmutAlihan wants to merge 7 commits into
tinyhumansai:mainfrom
UmutAlihan:self-hosted-decision-provider
Open

UmutAlihan wants to merge 7 commits into
tinyhumansai:mainfrom
UmutAlihan:self-hosted-decision-provider

Conversation

@UmutAlihan

Copy link
Copy Markdown

What

Adds JevProvider::SelfHosted (wire self_hosted, alias selfhosted) to the bus contract and engine, bumping CONTRACT_VERSION to 2.9 (additive).

An operator-declared Jev-compatible decisions endpoint — e.g. a self-hosted open decision model serving the Surogate decisions-v1 protocol — can now drive the Jev loops:

  • No approved route and no default model: both JevConfig::endpoint_url and JevConfig::model are required (JEV_INVALID_CONFIG otherwise).
  • The declared endpoint is trusted because the operator named it; Client::new remains the syntactic gate (absolute HTTP(S), no embedded credentials, no query or fragment, plain HTTP only on a literal loopback address).
  • The client is built exactly like first-party TypeSafe Jev at the declared endpoint, so a self-hosted model satisfies the first-party response check by echoing the requested model id.

Why

Hosts that run their own decision models (on-prem inference, no third-party Jev route) currently have no way to point the Jev loops at them: every provider has exactly one hardcoded approved endpoint. The allowlist's job — keeping provider credentials off unapproved routes — does not apply to a self-hosted endpoint, where the key and the endpoint are one operator-declared unit.

Verification

  • cargo test green for tinycomputer-bus, tinycomputer-engine, tinycomputer (bus 192+34 lib/doctest, engine 353, module 33+10), cargo clippy clean (pedantic), cargo fmt applied.
  • New tests: serde round-trip + alias, provider selection from private module config, required endpoint/model, malformed-URL rejection, trust semantics for declared endpoints.
  • Live-verified against a self-hosted decisions endpoint serving choice/noul/score questions with calibrated probabilities: response shape matches the first-party validation (answers keyed by question id, model echo).
  • Docs updated per the AGENTS.md contract-change table: desktop-module-contract.md version history, configuration.md, jev-runtime.md, architecture.md, MODULE.md, goal-loop.md.

A self-hosted open decision model — an operator-run Jev-compatible
decisions endpoint — can now drive the Jev loops. JevProvider::SelfHosted
(wire self_hosted, alias selfhosted) has no approved route and no default
model: JevConfig::endpoint_url and JevConfig::model are both required, the
declared endpoint is trusted because the operator named it, and
Client::new remains the syntactic gate (absolute HTTP(S), no embedded
credentials, no query or fragment, plain HTTP only on a literal loopback).
The client is built exactly like first-party TypeSafe Jev at the declared
endpoint, so a self-hosted model satisfies the first-party response check
by echoing the requested model id.
@tinysweeper

tinysweeper Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

Adds the self_hosted decision provider (contract 2.9), allowing operators to declare their own Jev-compatible endpoint. Contract version bumped to 2.9. Includes minor code refactors and documentation updates. All earlier concerns about the provider loop and compatibility test have been resolved; no active findings remain. Many files could not be reviewed due to retrieval failures, but the reviewed lanes confirm the change is sound.

State: Incomplete
Priority: none
Reviewed head: f748115e4b9d
Updated: 1790954005 (Unix time)

Review snapshot

Change surface Files Review signal Count
Production 6 Active findings 0
Tests 6 Noted findings 0
Documentation 6 Resolved findings 4
Configuration 0 Pending checks/questions 30

Completeness: Incomplete
Test assessment: Test coverage is assessed from changed tests and lane evidence; execution is not claimed without trusted check data.

What changed

Implements the self_hosted decision provider with required endpoint_url and model. Adds SelfHosted variant to JevProvider enum, updates runtime configuration and endpoint validation, bumps contract version, adds tests, and updates documentation. Includes minor refactors in accessibility modules and a test assertion improvement.

Features

  • Added — self_hosted decision provider: Allows operators to configure a custom Jev-compatible decision endpoint, with required endpoint_url and model. (crates/tinycomputer-bus/src/agentic/types/config.rs, crates/tinycomputer-engine/src/agentic/runtime.rs)
  • Modified — Contract version bump to 2.9: Enables the new provider and breaks compatibility with modules using contract version 2.8. (crates/tinycomputer-bus/src/version/mod.rs)
  • Internal refactor — Accessibility code improvements: Improves code quality in focus.rs, paste.rs, and permissions.rs. (crates/tinycomputer-accessibility/src/focus.rs, crates/tinycomputer-accessibility/src/paste.rs, crates/tinycomputer-accessibility/src/permissions.rs)
  • Internal refactor — Test assertion improvement in screen_tests.rs: Better test clarity. (crates/tinycomputer-cursor/src/screen/screen_tests.rs)

Tests

  • addition — Tests self_hosted config decoding, round-trip, and alias.: Validates the new provider configuration. (crates/tinycomputer-bus/src/agentic/agentic_tests.rs)
  • addition — Tests self_hosted runtime configuration: requires endpoint and model, trusts declared endpoint, rejects malformed URLs.: Verifies correct runtime behavior for self_hosted provider. (crates/tinycomputer-engine/src/agentic/agentic_tests/resolve_tests.rs)
  • addition — Tests self_hosted from_config: accepts valid config, rejects missing endpoint or model.: Validates configuration parsing. (crates/tinycomputer/src/tinybus_module/tinybus_module_tests/config_tests.rs)
  • modification — Updates version assertions to (2,9) in version_tests and public_api_tests.: Reflects contract version change. (crates/tinycomputer-bus/src/version/version_tests.rs, crates/tinycomputer/tests/public_api_tests.rs)

Findings

No active actionable findings.

Resolved this pass

  • Exclude SelfHosted from the provider loop that expects a hosted route
  • Reconcile the compatibility test with the unchanged implementation
  • Reconcile the compatibility test with the unchanged implementation
  • Exclude SelfHosted from the provider loop that expects a hosted route

Could not review: MODULE.md, crates/tinycomputer-accessibility/src/focus.rs, crates/tinycomputer-accessibility/src/paste.rs, crates/tinycomputer-accessibility/src/permissions.rs, crates/tinycomputer-bus/src/agentic/agentic_tests.rs, crates/tinycomputer-bus/src/agentic/types/config.rs, crates/tinycomputer-bus/src/version/mod.rs, crates/tinycomputer-bus/src/version/version_tests.rs, crates/tinycomputer-cursor/src/screen/screen_tests.rs, crates/tinycomputer-engine/src/agentic/agentic_tests/resolve_tests.rs, crates/tinycomputer-engine/src/agentic/runtime.rs, crates/tinycomputer/src/tinybus_module/tinybus_module_tests/config_tests.rs, crates/tinycomputer/tests/public_api_tests.rs, docs/crates/tinycomputer-bus/goal-loop.md, docs/crates/tinycomputer-engine/jev-runtime.md, docs/crates/tinycomputer/configuration.md, docs/technical/architecture.md, docs/technical/specs/desktop-module-contract.md

Before merge

  • Complete the critique review for MODULE.md, crates/tinycomputer-accessibility/src/focus.rs, crates/tinycomputer-accessibility/src/paste.rs, crates/tinycomputer-accessibility/src/permissions.rs, crates/tinycomputer-bus/src/agentic/agentic_tests.rs, crates/tinycomputer-bus/src/agentic/types/config.rs, crates/tinycomputer-engine/src/agentic/agentic_tests/resolve_tests.rs, crates/tinycomputer-engine/src/agentic/runtime.rs, crates/tinycomputer-bus/src/version/mod.rs, crates/tinycomputer-bus/src/version/version_tests.rs, crates/tinycomputer-cursor/src/screen/screen_tests.rs, crates/tinycomputer/src/tinybus_module/tinybus_module_tests/config_tests.rs, crates/tinycomputer/tests/public_api_tests.rs, docs/crates/tinycomputer-bus/goal-loop.md, docs/crates/tinycomputer-engine/jev-runtime.md, docs/crates/tinycomputer/configuration.md, docs/technical/architecture.md, docs/technical/specs/desktop-module-contract.md.
  • Complete the security review for crates/tinycomputer-accessibility/src/permissions.rs, crates/tinycomputer-accessibility/src/focus.rs, crates/tinycomputer-accessibility/src/paste.rs, crates/tinycomputer-bus/src/agentic/agentic_tests.rs, crates/tinycomputer-bus/src/agentic/types/config.rs, crates/tinycomputer-engine/src/agentic/agentic_tests/resolve_tests.rs, crates/tinycomputer-engine/src/agentic/runtime.rs, crates/tinycomputer-bus/src/version/mod.rs, crates/tinycomputer-bus/src/version/version_tests.rs, crates/tinycomputer-cursor/src/screen/screen_tests.rs, crates/tinycomputer/src/tinybus_module/tinybus_module_tests/config_tests.rs, crates/tinycomputer/tests/public_api_tests.rs.

How this fits together

flowchart LR
  n0["focused_text_context_verbose<br/>changed"]:::changed
  n1["restore_focus_to_app<br/>changed"]:::changed
  n2["JevConfig<br/>changed"]:::changed
  n3["JevProvider<br/>changed"]:::changed
  n4["configure"]:::impacted
  n5["command_output_with_timeout"]:::impacted
  n6["Err"]:::impacted
  n7["JevConfiguration"]:::impacted
  n8["focused_text_via_osascript"]:::impacted
  n0 -->|calls| n6
  n0 -->|calls| n8
  n1 -->|calls| n6
  n2 -->|uses| n3
  n4 -->|uses| n2
  n4 -->|calls| n6
  n4 -->|uses| n7
  n5 -->|calls| n6
  n5 -->|tests| n6
  n7 -->|uses| n3
  n8 -->|calls| n5
  n8 -->|calls| n6
  classDef changed fill:#0d4429,stroke:#238636,color:#e6edf3
  classDef impacted fill:#161b22,stroke:#6e7681,color:#c9d1d9
  classDef flagged fill:#5a1e02,stroke:#d93f0b,color:#ffffff
  classDef blocking fill:#67060c,stroke:#f85149,color:#ffffff
Loading
Agent review details

critique

  • Conclusion: Neutral
  • Scope reviewed: incomplete; unanswered: MODULE.md, crates/tinycomputer-accessibility/src/focus.rs, crates/tinycomputer-accessibility/src/paste.rs, crates/tinycomputer-accessibility/src/permissions.rs, crates/tinycomputer-bus/src/agentic/agentic_tests.rs, crates/tinycomputer-bus/src/agentic/types/config.rs, crates/tinycomputer-engine/src/agentic/agentic_tests/resolve_tests.rs, crates/tinycomputer-engine/src/agentic/runtime.rs, crates/tinycomputer-bus/src/version/mod.rs, crates/tinycomputer-bus/src/version/version_tests.rs, crates/tinycomputer-cursor/src/screen/screen_tests.rs, crates/tinycomputer/src/tinybus_module/tinybus_module_tests/config_tests.rs, crates/tinycomputer/tests/public_api_tests.rs, docs/crates/tinycomputer-bus/goal-loop.md, docs/crates/tinycomputer-engine/jev-runtime.md, docs/crates/tinycomputer/configuration.md, docs/technical/architecture.md, docs/technical/specs/desktop-module-contract.md
  • Lane summary: Reviewed 0 files; 0 findings. 18 files could not be reviewed: MODULE.md, crates/tinycomputer-accessibility/src/focus.rs, crates/tinycomputer-accessibility/src/paste.rs, crates/tinycomputer-accessibility/src/permissions.rs, crates/tinycomputer-bus/src/agentic/agentic_tests.rs, crates/tinycomputer-bus/src/agentic/types/config.rs, crates/tinycomputer-engine/src/agentic/agentic_tests/resolve_tests.rs, crates/tinycomputer-engine/src/agentic/runtime.rs, crates/tinycomputer-bus/src/version/mod.rs, crates/tinycomputer-bus/src/version/version_tests.rs, crates/tinycomputer-cursor/src/screen/screen_tests.rs, crates/tinycomputer/src/tinybus_module/tinybus_module_tests/config_tests.rs, crates/tinycomputer/tests/public_api_tests.rs, docs/crates/tinycomputer-bus/goal-loop.md, docs/crates/tinycomputer-engine/jev-runtime.md, docs/crates/tinycomputer/configuration.md, docs/technical/architecture.md, docs/technical/specs/desktop-module-contract.md.

security

  • Conclusion: Neutral
  • Scope reviewed: incomplete; unanswered: crates/tinycomputer-accessibility/src/permissions.rs, crates/tinycomputer-accessibility/src/focus.rs, crates/tinycomputer-accessibility/src/paste.rs, crates/tinycomputer-bus/src/agentic/agentic_tests.rs, crates/tinycomputer-bus/src/agentic/types/config.rs, crates/tinycomputer-engine/src/agentic/agentic_tests/resolve_tests.rs, crates/tinycomputer-engine/src/agentic/runtime.rs, crates/tinycomputer-bus/src/version/mod.rs, crates/tinycomputer-bus/src/version/version_tests.rs, crates/tinycomputer-cursor/src/screen/screen_tests.rs, crates/tinycomputer/src/tinybus_module/tinybus_module_tests/config_tests.rs, crates/tinycomputer/tests/public_api_tests.rs
  • Lane summary: Reviewed 0 files; 0 findings. 12 files could not be reviewed: crates/tinycomputer-accessibility/src/permissions.rs, crates/tinycomputer-accessibility/src/focus.rs, crates/tinycomputer-accessibility/src/paste.rs, crates/tinycomputer-bus/src/agentic/agentic_tests.rs, crates/tinycomputer-bus/src/agentic/types/config.rs, crates/tinycomputer-engine/src/agentic/agentic_tests/resolve_tests.rs, crates/tinycomputer-engine/src/agentic/runtime.rs, crates/tinycomputer-bus/src/version/mod.rs, crates/tinycomputer-bus/src/version/version_tests.rs, crates/tinycomputer-cursor/src/screen/screen_tests.rs, crates/tinycomputer/src/tinybus_module/tinybus_module_tests/config_tests.rs, crates/tinycomputer/tests/public_api_tests.rs. 6 files were not security-reviewed: MODULE.md (prose or tabular data), docs/crates/tinycomputer-bus/goal-loop.md (prose or tabular data), docs/crates/tinycomputer-engine/jev-runtime.md (prose or tabular data), docs/crates/tinycomputer/configuration.md (prose or tabular data), docs/technical/architecture.md (prose or tabular data), and 1 more.

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: Adds the `SelfHosted` Jev provider variant (contract 2.9), an operator-declared endpoint with required model and endpoint_url. The runtime gate, config parsing, and test coverage look sound. No new findings. _Code retrieval was unavailable (model: ladder embeddings returned 502 Bad Gateway: {"error":{"message":"no rung of ladder vectors could serve the request","skipped":[{"model":"text-embedding-bge-m3","provider":"venice","reason":"rate limited, retry in 26s","rung":0}],"type":"ladder_router_error"}}), so this review saw the diff alone._ _3 memory call(s) failed (model: cortex: v1/answer: timed out after 20s), so this review saw part of what the engine holds._

commits

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: Nothing sensitive found in what this pull request commits.

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: This pull request adds the `SelfHosted` Jev decision provider, bumps the contract to 2.9, and routes it through the existing client and response-check machinery. The implementation matches the description and the earlier concerns about the compatibility test and the provider loop are resolved, so the change is sound to merge. _Code retrieval was unavailable (model: ladder embeddings returned 502 Bad Gateway: {"error":{"message":"no rung of ladder vectors could serve the request","skipped":[{"model":"text-embedding-bge-m3","provider":"venice","reason":"rate limited, retry in 26s","rung":0}],"type":"ladder_router_error"}}), so this review saw the diff alone._ _3 memory call(s) failed (model: cortex: v1/answer: timed out after 20s), so this review saw part of what the engine holds._

e2e

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: No end-to-end harness in this repository: no e2e test files and no e2e workflow.
Evidence and run details
  • Models: deepseek/deepseek-v4-flash
  • Spend: $0.004745
  • Tokens: 88663 input · 17394 output · 28708 cached · 0 embedding
Head State Pass summary
63b349c450c9 incomplete 1 active finding(s), 0 resolved finding(s) (at 1790942227)
63b349c450c9 incomplete 0 active finding(s), 1 resolved finding(s) (at 1790943221)
f748115e4b9d incomplete 1 active finding(s), 2 resolved finding(s) (at 1790952929)
f748115e4b9d incomplete 0 active finding(s), 2 resolved finding(s) (at 1790953692)
f748115e4b9d incomplete 0 active finding(s), 4 resolved finding(s) (at 1790954005)

tinysweeper 0.1.0

@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: ec40ca10-3d3d-4a8e-bdf6-54480d77b5a0

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Comment @coderabbitai help to get the list of available commands.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tinysweeper found nothing blocking, but could not review everything, so this is not an approval: MODULE.md, crates/tinycomputer-bus/src/agentic/agentic_tests.rs, crates/tinycomputer-bus/src/agentic/types/config.rs, crates/tinycomputer-bus/src/version/mod.rs, crates/tinycomputer-bus/src/version/version_tests.rs, crates/tinycomputer-engine/src/agentic/agentic_tests/resolve_tests.rs, crates/tinycomputer-engine/src/agentic/runtime.rs, crates/tinycomputer/src/tinybus_module/tinybus_module_tests/config_tests.rs and 8 more.

$0.0000 · 0 in / 0 out · 969 embedded · ladder/vectors

The stable toolchain roll (1.96.1 -> 1.98.1) turned four lints in
tinycomputer-accessibility into CI failures for every open PR, including
this one:

- focus.rs: push_str with a format! allocation -> inline format args
- paste.rs: positional format args -> inline format args
- permissions.rs: add #[must_use] to the macOS/Windows
  detect_microphone_permission, and a single-pattern match -> if let

Behavior is unchanged; cargo clippy --all-targets --all-features
-D warnings is green across the workspace under both 1.96.1 and 1.98.1,
and tinycomputer-accessibility tests pass.
@UmutAlihan

Copy link
Copy Markdown
Author

Pushed d1c2c38f to fix the Rust CI failure.

Root cause: not this PR's diff — the stable toolchain roll (1.96.1 → 1.98.1) turned four pre-existing lints in tinycomputer-accessibility into -D warnings failures for every open PR (the legacy-test-renames and release PRs fail identically). This PR happened to surface it first because tinycomputer-accessibility is checked early in the workspace.

The fix commit is mechanical and behavior-preserving:

  • focus.rs: push_str(&format!(…)) → push_str with inline format args
  • paste.rs: positional format args → inline format args
  • permissions.rs: #[must_use] on the macOS/Windows detect_microphone_permission, single-pattern match → if let

Verified locally with CI's exact toolchain and flags (rustup run stable = 1.98.1, cargo clippy --all-targets --all-features -- -D warnings): workspace-wide zero errors. Full test suite (tinycomputer-bus 192+34, tinycomputer-engine 353, tinycomputer 33+10) green, cargo fmt clean. The feature commit 9b8b9ad3 is untouched.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tinysweeper found nothing blocking, but could not review everything, so this is not an approval: crates/tinycomputer-accessibility/src/focus.rs, crates/tinycomputer-accessibility/src/paste.rs, crates/tinycomputer-accessibility/src/permissions.rs, tinysweeper/description, tinysweeper/tests.

$0.0000 · 0 in / 0 out · 1,109 embedded · ladder/vectors

Stable 1.99.0 (2026-09-28) adds clippy::assert-is-empty, denying the
assert!(x.is_empty()) idiom across the workspace's test code — every
open PR fails CI on it. Convert each flagged site to assert_eq! /
assert_ne! so the compared value prints on failure:

- Vec fields: assert_eq!(x, []) (with the type annotation where
  inference needs it), Vec::new() for non-inferable element types
- Strings: assert_eq!(x, "")
- MutexGuard<Vec>: deref the guard
- the TERMINAL_NAMES const sanity check: assert_ne!(len, 0)
- HashMap sites are not matched by the lint and are unchanged

Applied with cargo clippy --fix where the suggestion was
machine-applicable, by hand where it was not. Behavior-preserving;
cargo clippy --all-targets --all-features -D warnings is green
workspace-wide under 1.96.1, 1.98.1, and 1.99.0, and the full test
suite passes.
@UmutAlihan

Copy link
Copy Markdown
Author

Follow-up: d5385fd4 fixed the 1.98 roll's lints in tinycomputer-accessibility, but stable rolled again to 1.99.0 (2026-09-28), which adds clippy::assert-is-empty — the previous CI run failed on that in tinycomputer-desktop/tinycomputer-accessibility test code.

Pushed 64e42a74: converts every flagged assert!(x.is_empty()) to assert_eq!/assert_ne! (value now prints on failure), applied with cargo clippy --fix where machine-applicable and by hand where not. 38 files, all test code, behavior-preserving.

Verified: cargo clippy --all-targets --all-features -- -D warnings green workspace-wide under 1.96.1, 1.98.1, and 1.99.0; full test suite passes; cargo fmt --check clean. The feature commit 9b8b9ad3 remains untouched. Note for other open PRs: they'll hit the same 1.99 lint — this branch can be used as a reference for the mechanical fix.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tinysweeper found nothing blocking, but could not review everything, so this is not an approval: crates/tinycomputer-accessibility/src/terminal_tests.rs, crates/tinycomputer-browser/src/outputs/outputs_tests.rs, crates/tinycomputer-browser/src/sessions/sessions_tests/artifacts_tests.rs, crates/tinycomputer-browser/src/sessions/sessions_tests/lifecycle_tests.rs, crates/tinycomputer-browser/src/surface/surface_tests/cursor_tests.rs, crates/tinycomputer-browser/src/surface/surface_tests/tree_tests.rs, crates/tinycomputer-bus/src/agent/agent_tests.rs, crates/tinycomputer-bus/src/agentic/agentic_tests.rs and 32 more.

$0.0000 · 0 in / 0 out · 1,192 embedded · ladder/vectors

globe_tests.rs's non_macos_listener_entry_points_report_unsupported is
#[cfg(not(target_os = "macos"))], so a macOS clippy run never compiles
it and the previous commit missed its assert!(polled.events.is_empty()).
Convert it like the rest. This was the only remaining single-form
is_empty assert inside a non-macOS-gated block; verified by sweeping
every cfg(not(macos))/linux/windows-gated file for the pattern.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tinysweeper found nothing blocking, but could not review everything, so this is not an approval: crates/tinycomputer-accessibility/src/globe_tests.rs, tinysweeper/description, tinysweeper/tests.

$0.0000 · 0 in / 0 out · 1,200 embedded · ladder/vectors

@UmutAlihan

Copy link
Copy Markdown
Author

Hi @senamakel — gentle nudge for a review when you have a moment 🙂

All CI checks are green on the latest head (87f50b28): Rust (clippy + tests), Docs, MSRV, Supply chain, and tinysweeper/review. The feature commit is 9b8b9ad3; the three commits after it are mechanical fixes for the pre-existing clippy failures the stable toolchain rolls (1.98 → 1.99) caused across all open PRs — happy to split those into a separate PR if you'd rather keep this one feature-only.

Summary of the change: adds a self_hosted decision provider (contract 2.9) so hosts can point the Jev loops at an operator-run Jev-compatible decisions endpoint — e.g. an on-prem open decision model — with a required endpoint_url and model, no approved-route allowlist (the declared endpoint is the route), and Client::new still enforcing URL shape. Docs and tests included per the contract-change table in AGENTS.md.

No rush at all — just let me know if anything should change. Thanks!

@senamakel senamakel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this. The self_hosted design is sound: the endpoint and model are both required, Client::new stays the syntactic gate, the api key is still redacted in Debug, and the provider is only reachable through private module config, so an agent cannot point the key at an arbitrary host. I am not merging yet because of one correctness regression.

Blocking: crates/tinycomputer-accessibility/src/focus.rs loses its interpolation.

// before
helper_error.push_str(&format!("; osascript fallback failed: {fallback_err}"));
// after
helper_error.push_str("; osascript fallback failed: {fallback_err}");

The format! was dropped but the argument stayed inside a plain string literal. The error text now contains a literal {fallback_err} and the real error is lost. This is a macOS-only path, so Linux CI cannot catch it. Please restore the formatting, for example use std::fmt::Write; let _ = write!(helper_error, "; osascript fallback failed: {fallback_err}");.

Heads-up: overlap with main. Main CI has been red since the Rust 1.99 toolchain landed (clippy::assert_is_empty under -D warnings). Several of the test-file edits here are the same fix. I am fixing main's lint failures in a separate sync PR, so you will need to merge main into this branch afterwards. Conflicts should be limited to those test-only edits, and you can take main's version of them.

Minor, non-blocking: with self_hosted the Describe capabilities echo endpoint_url. Client::new rejects embedded credentials, so it cannot carry a secret, but docs could say operators should not put tokens in the path or query.

Resolves the expected overlap with tinyhumansai#70: both branches fixed the same
clippy::assert_is_empty sites with slightly different spellings; main's
versions are taken, as agreed in review.
… endpoint URLs

- focus.rs (blocking review finding): the 1.98 lint fix dropped format!
  but left {fallback_err} inside a plain string literal, so the macOS
  osascript-fallback error text contained a literal placeholder and the
  real error was lost. Restore interpolation with fmt::Write::write!.
- configuration.md, jev-runtime.md (non-blocking review suggestion):
  state that self_hosted authentication belongs in api_key alone — keep
  tokens out of the endpoint_url path or query, since Describe echoes
  the configured endpoint_url in its capabilities.
@UmutAlihan

Copy link
Copy Markdown
Author

Both review points are addressed on the new head (63b349c):

Blocking — focus.rs interpolation restored. The 1.98 lint fix had dropped format! but left {fallback_err} inside the plain string literal, so the osascript-fallback error text carried a literal placeholder and the real error was lost. It now uses fmt::Write::write! per your suggestion:

use std::fmt::Write as _;
let _ = write!(helper_error, "; osascript fallback failed: {fallback_err}");

Since Linux CI cannot compile this path, I verified it compiles natively on a macOS host (stable 1.99 clippy --all-targets --all-features covers the #[cfg(target_os = "macos")] function there), cross-checked cargo check --target aarch64-apple-darwin, and compiled it under the MSRV 1.89 toolchain. There is no test seam for that branch without refactoring the helper/osascript calls, so I did not add a test — happy to add one if you would prefer the seam.

Docs — no tokens in endpoint_url path/query. configuration.md and jev-runtime.md now state that authentication belongs in api_key alone and tokens should stay out of the URL path or query, since Describe echoes the configured endpoint_url in its capabilities.

Merged main. Your sync PR #70 landed, so I merged it into this branch as suggested. All five conflicts were the same benign overlap (both branches fixed the same assert_is_empty sites with different spellings); main's versions are taken. The merge commit is pure — the review fixes are a separate commit (63b349c) on top.

Local verification on the new head, matching CI: cargo fmt --all -- --check clean; cargo clippy --all-targets --all-features -- -D warnings clean (1.99.0); cargo test 1085 passed / 0 failed; cargo test --all-features 1105 passed / 0 failed; cargo doc with -D warnings clean; the tinycomputer-bus transport-free assertion holds; the bundled example runs.

One pre-existing note, unrelated to this PR: paste::tests::the_system_platform_reports_a_missing_display_instead_of_panicking fails on a macOS host with --all-features — its guard checks DISPLAY/WAYLAND_DISPLAY (always unset on macOS) and then asserts insert_text errors, but on a real desktop it succeeds. It fails identically on origin/main and is invisible to Linux CI; probably worth gating #[cfg(target_os = "linux")] in a sync PR.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 1 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0062 · 61,806 in / 14,787 out · 28,160 cached (46%) · deepseek/deepseek-v4-flash
tests:       $0.0036 · 33,751 in / 9,681 out  · 15,872 cached (47%) · deepseek/deepseek-v4-flash
description: $0.0016 · 15,593 in / 1,027 out  · 0 cached (0%)       · deepseek/deepseek-v4-flash

JevProvider::TinyHumansOpenRouter,
JevProvider::OpenJev,
JevProvider::Sage,
JevProvider::SelfHosted,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high tests confident

Exclude SelfHosted from the provider loop that expects a hosted route

Adding JevProvider::SelfHosted to the providers list in an_endpoint_cannot_be_reused_across_providers causes the test to panic because approved_endpoint(SelfHosted) returns None and the code immediately calls .expect("a hosted route") on it. This will cause every test run to fail. Either skip SelfHosted in this loop (since it has no approved endpoint) or handle the None case before unwrapping.

[RULE] failing-test ·

@UmutAlihan

Copy link
Copy Markdown
Author

@tinysweeper please re-review the current head (63b349c). The previous tests lane ran with code retrieval unavailable (ladder embeddings 502, rate limited) and saw the diff alone; its one finding appears to be a false positive — only_each_providers_own_endpoint_is_approved already excludes SelfHosted from the hosted-route loop and asserts approved_endpoint(SelfHosted) == None separately, and the full suite is green (Rust CI passed, 1085 + 1105 tests locally).

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tinysweeper found nothing blocking, but could not review everything, so this is not an approval: MODULE.md, crates/tinycomputer-accessibility/src/focus.rs, crates/tinycomputer-accessibility/src/paste.rs, crates/tinycomputer-accessibility/src/permissions.rs, crates/tinycomputer-bus/src/agentic/agentic_tests.rs, crates/tinycomputer-bus/src/agentic/types/config.rs, crates/tinycomputer-bus/src/version/mod.rs, crates/tinycomputer-bus/src/version/version_tests.rs and 10 more.

             $0.0050 · 51,982 in / 6,811 out · 12,544 cached (24%) · deepseek/deepseek-v4-flash
tests:       $0.0017 · 12,963 in / 3,186 out · 0 cached (0%)       · deepseek/deepseek-v4-flash
description: $0.0006 · 12,609 in / 2,149 out · 12,544 cached (99%) · deepseek/deepseek-v4-flash

@UmutAlihan

Copy link
Copy Markdown
Author

@senamakel All three points from your review are addressed on the new head (63b349c):

  • focus.rs interpolation (blocking) — restored with fmt::Write::write!, exactly as you suggested. Since Linux CI cannot compile this macOS-only path, I verified it natively on a macOS host (stable 1.99 clippy --all-targets --all-features compiles the #[cfg(target_os = "macos")] fn there), cross-checked cargo check --target aarch64-apple-darwin, and compiled it under the 1.89 MSRV toolchain.
  • Docs (non-blocking) — configuration.md and jev-runtime.md now state that authentication belongs in api_key alone and tokens should stay out of the URL path or query, since Describe echoes the configured endpoint_url.
  • Merged main — your sync PR Sync vendored submodules to latest and fix red main CI #70 landed, so I merged it into this branch as suggested. All five conflicts were the same benign assert_is_empty overlap; main's versions are taken. The merge commit is pure — the review fixes are the separate commit 63b349c on top.

CI is green on the new head (Rust, Docs, MSRV, Supply chain, tinysweeper/review). The one tinysweeper/tests failure was a false positive from its degraded code-retrieval run and cleared on re-review. Full verification details in my earlier comment above.

Takes main's version of detect_microphone_permission: the cpal 0.18
bump (tinyhumansai#72) changed the device-name API (description().name()), which
overlaps the branch's 1.98 if-let lint refactor.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 1 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0078 · 71,761 in / 8,916 out · 3,072 cached (4%) · deepseek/deepseek-v4-flash
tests:       $0.0020 · 16,259 in / 3,728 out · 1,280 cached (8%) · deepseek/deepseek-v4-flash
description: $0.0019 · 15,905 in / 2,926 out · 1,280 cached (8%) · deepseek/deepseek-v4-flash

assert!(is_compatible((2, 97)));
// 2.9 accepts the `self_hosted` decision provider: a 2.9 host may
// configure it, which a 2.8 module refuses.
assert!(!is_compatible((2, 8)));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high tests confident

Reconcile the compatibility test with the unchanged implementation

is_compatible implements module.0 == CONTRACT_VERSION.0 && module.1 <= CONTRACT_VERSION.1. With CONTRACT_VERSION now (2,9), it returns true for a module reporting (2,8) because 8 <= 9. The test a_newer_minor_on_the_module_side_binds (and the doc example in mod.rs) now assert !is_compatible((2,8)), which will fail. Either change is_compatible to enforce the new policy (e.g., strict equality) or correct the test expectation to true and add a separate check that prevents SelfHosted config from being sent to a 2.8 module.

[RULE] failing-test ·

@tinysweeper tinysweeper Bot removed the priority: p3 label Oct 2, 2026
@UmutAlihan

Copy link
Copy Markdown
Author

@tinysweeper please re-review head f748115. The tests lane again ran with code retrieval unavailable (ladder embeddings 502) and saw the diff alone; its finding inverts the comparison — binds requires module_minor >= host_minor, so is_compatible((2, 8)) against contract (2, 9) is false and the assertion is correct. The suite is green locally (1085 + 1105 tests) and the Rust CI check passed on this head.

@UmutAlihan

Copy link
Copy Markdown
Author

@senamakel Heads-up while waiting on re-review: main moved again (cpal 0.18 bump #72 + v0.9.1), which re-conflicted this branch. I merged it and resolved the permissions.rs overlap by keeping main's cpal 0.18 device API (description().name()) with this branch's pedantic-clean if let + #[must_use] shape — the merged result passes cargo clippy --all-targets --all-features -- -D warnings, fmt, and the full test suite (1085 + 1105 passed) locally.

One thing you may want for a sync PR: current main (2b0ee5c) fails that exact clippy command on 1.99.0 with 4 pedantic errors, even though its CI run reports success:

  • focus.rs:135 — format!(..) appended to existing String (push_str(&format!(...)); the write! form from this branch resolves it and keeps the interpolation you flagged)
  • paste.rs:223 — variables can be used directly in the format string
  • permissions.rs:150 — missing #[must_use] on detect_microphone_permission
  • permissions.rs:153 — match for a single pattern → if let

(Your CI run for #72 may have used an older clippy; on 1.99.0 these fire.) The new head is f748115; repo CI on it is green (Rust, Docs, MSRV, Supply chain). The pending tinysweeper/tests failure is another degraded-retrieval false positive — it inverted the binds comparison direction; re-review requested.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tinysweeper found nothing blocking, but could not review everything, so this is not an approval: MODULE.md, crates/tinycomputer-accessibility/src/focus.rs, crates/tinycomputer-accessibility/src/paste.rs, crates/tinycomputer-accessibility/src/permissions.rs, crates/tinycomputer-bus/src/agentic/agentic_tests.rs, crates/tinycomputer-bus/src/agentic/types/config.rs, crates/tinycomputer-bus/src/version/mod.rs, crates/tinycomputer-bus/src/version/version_tests.rs and 10 more.

             $0.0047 · 88,663 in / 17,394 out · 28,708 cached (32%) · deepseek/deepseek-v4-flash
tests:       $0.0005 · 16,246 in / 108 out    · 0 cached (0%)       · deepseek/deepseek-v4-flash
description: $0.0005 · 32,042 in / 16,221 out · 28,196 cached (88%) · deepseek/deepseek-v4-flash

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants