feat(telemetry): anonymous PostHog usage telemetry with funnel instrumentation - #1908
Conversation
…mentation Adds opt-out anonymous usage telemetry so install funnel, interview → seed → run → evolve conversion, entry surface (terminal CLI vs in-agent ooo), and per-backend success rates become measurable across all runtimes. - src/ouroboros/telemetry.py: stdlib-only client (urllib + daemon thread, bounded queue, never raises/blocks), random UUID identity in ~/.ouroboros/telemetry.json, embedded public write-only project key - MCPServerAdapter.call_tool chokepoint captures every ouroboros_* tool call (both transports + codex intercept) with ok/duration/error_type; polling tools sampled 1/50 with re-weighting property - create_ouroboros_server stamps resolved runtime/llm backends onto all events; CLI callback captures direct `ooo <cmd>` usage (mcp/job/dispatch excluded so serve boots don't inflate terminal counts) - install.sh pings install_started/install_completed (method, runtime, detected runtime count) under the same privacy contract - Opt out via DO_NOT_TRACK / OUROBOROS_TELEMETRY=0 / config telemetry.enabled; one-time first-run notice; TELEMETRY.md documents the full contract: whitelist of events, declared uses incl. public aggregate stats, fixed counting rule, k-anonymity floor, append-only changelog - tests/conftest.py force-disables telemetry suite-wide so tests can never post real events Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: REQUEST_CHANGES
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | ee4d2c6ffc319ea9eef4e3f622f9ad87e4e2226e |
| Request ID | req_1785984259_616-retry-1 |
| Review record | fafc457a-5fa1-4293-ad0e-5754d4118201 |
What Improved
- Adds a centralized, bounded, stdlib-only telemetry transport with anonymous UUID identity, event batching, polling sampling, and failure isolation.
- Adds telemetry configuration, opt-out documentation, CLI/MCP/install instrumentation, and hermetic telemetry tests.
Issue Requirements
| Requirement | Status |
|---|---|
| Anonymous opt-out telemetry across all supported runtimes | Partially met — core instrumentation exists, but hostile project environments can force or redirect it and several execution paths report only submission outcomes. |
| Measure install, interview → seed → run → evolve, entry-surface, and per-backend success funnels | Partially met — funnel events exist, but asynchronous start receipts are treated as run success and validation/security failures are omitted. |
Use MCPServerAdapter.call_tool as a single instrumentation chokepoint, with CLI and installer events |
Partially met — successful handler calls are covered, but pre-handler SDK validation and adapter early returns bypass capture. |
| Sample high-frequency polling tools at 1/50 with reweighting metadata | Partially met — implemented for the explicit set, but the set omits public status-query tools. |
| Ship a truthful telemetry trust contract and event whitelist | Partially met — the event table is useful, but runtime behavior violates opt-out/counting promises and the source-location statement is inaccurate. |
Support DO_NOT_TRACK, OUROBOROS_TELEMETRY=0, and telemetry.enabled: false as complete opt-outs |
Not met — installer telemetry ignores the config opt-out, malformed config enables collection, and project .env can override the persisted opt-out. |
| Show a one-time first-run notice | Partially met — the CLI notice is stateful, but the installer sends its first event before notice and failed installs may never show one. |
| Use a random stable UUID and remove it on normal uninstall | Met — the UUID is random and stored under ~/.ouroboros, which default uninstall removes with the data directory. |
| Use stdlib-only, bounded, best-effort transport that never raises into commands | Met for exception isolation and queue bounds; synchronous config/state access remains outside the background transport. |
| Keep tests from sending production telemetry | Met — suite-wide disablement and fake transport/key injection are present. |
Prior Findings Status
No prior ouroboros-agent review rounds were present. No previous findings required maintenance, modification, or withdrawal.
Blockers
| # | File:Line | Severity | Finding |
|---|---|---|---|
| 1 | src/ouroboros/telemetry.py:99 | BLOCKING | The PostHog API key and destination are read from os.environ, but importing config.loader loads the current project's untrusted .env into that same environment without denying OUROBOROS_POSTHOG_HOST, OUROBOROS_POSTHOG_API_KEY, or OUROBOROS_TELEMETRY. A cloned repository can therefore force telemetry on despite telemetry.enabled: false and redirect the stable anonymous ID plus runtime metadata to an attacker-controlled or local endpoint. A subprocess probe reproduced is_enabled() == True and an attacker-provided host while the user config explicitly disabled telemetry. These keys must be denied from project .env input or resolved exclusively from a trusted environment source. |
| 2 | src/ouroboros/config/loader.py:1436 | BLOCKING | The config opt-out fails open: any ConfigError from the full configuration returns True. An explicit telemetry.enabled: false is therefore ignored whenever an unrelated stale or invalid setting makes OuroborosConfig validation fail. A focused probe with telemetry disabled and an invalid logging value returned True. Privacy opt-outs must remain effective independently of unrelated configuration validity, or configuration errors must disable telemetry fail-closed. |
| 3 | scripts/install.sh:100 | BLOCKING | Installer telemetry implements only the two environment-variable opt-outs and never reads ~/.ouroboros/config.yaml, contradicting the documented promise that any of the three opt-out paths disables telemetry completely. It also emits install_started at line 191 before showing any notice at line 703; failure exits can therefore send an event without ever displaying the notice. A probe with telemetry.enabled: false captured a real /capture/ request and no notice. Honor the persisted opt-out before the first ping and disclose collection before that ping. |
| 4 | src/ouroboros/telemetry.py:70 | BLOCKING | ouroboros_start_execute_seed is classified as a successful run whenever its handler returns Result.ok, but that handler explicitly returns immediately after queuing background work; the job can later fail, be cancelled, or fail verification. No telemetry is emitted from the durable terminal job boundary. Consequently the documented “successful verified run” weekly-active-user rule and per-backend success rates cannot be computed truthfully and will count queue acceptance as product success. Emit terminal outcome telemetry from the durable job/execution completion boundary and keep start receipts distinct from successful verified runs. |
Follow-up Findings
src/ouroboros/mcp/server/adapter.py:970[warning] The claimed singlecall_toolchokepoint does not instrument every invocation or failure. Unknown tools and security-check failures return beforecapture_tool_call, while SDK schema validation at lines 106–118 rejects malformed/missing arguments beforeMCPServerAdapter.call_toolis entered at all. These common failure classes disappear fromcommand_run, biasing the advertised success-rate metric. Instrument the outer request envelope or ensure every return and validation failure emits exactly one sanitized event, with regression tests preventing duplicates.
| # | File:Line | Priority | Confidence | Suggestion |
|---|-----------|----------|------------|------------|
| 1 | src/ouroboros/telemetry.py:47 | Medium | Medium | Audit the polling roster against all public read-only status tools.ouroboros_lineage_statusandouroboros_project_statusare omitted even though status tools can be repeatedly queried, so the promised 1/50 sampling policy is not structurally complete. |
Non-blocking Suggestions
| 1 | TELEMETRY.md:89 | Documentation | “If it's not in those two places, it isn't collected” is inaccurate because collection triggers and properties also live in cli/main.py, cli/commands/mcp.py, and mcp/server/adapter.py. List all instrumentation call sites so the privacy audit guidance is truthful. |
Test Coverage Notes
tests/unit/test_telemetry.py: 20 passed.tests/unit/config/test_loader_env.py: 179 passed.tests/unit/scripts/test_install_runtime_selection.py: 29 passed.tests/unit/mcp/server/test_adapter.py: 64 passed, 5 skipped, and 10 failed because the review environment lacks the optionalmcppackage; failures were confined to SDK/serve tests requiring that extra.- Independent probes reproduced project
.envendpoint redirection and forced enablement, malformed-config fail-open behavior, and installer transmission despitetelemetry.enabled: false. - New tests exercise the telemetry module directly but do not cover installer opt-out/notice ordering, hostile project
.envkeys, malformed persisted config, adapter early-return failures, or durable background-job outcomes.
Design Notes
Centralizing serialization and transport in one module is a sound direction, but telemetry is a cross-cutting trust boundary. Enablement, endpoint selection, and success classification currently have multiple inconsistent sources of truth.
Design / Roadmap Gate
The changed boundary handles persistent identity, operator-owned opt-out state, untrusted project environment values, MCP request classification, and durable asynchronous execution. Current behavior is not fail-closed for privacy preferences, permits project-controlled destination redirection, and cannot implement the declared verified-success counting rule. These are contract and security failures rather than cosmetic telemetry inaccuracies.
Directional Notes
Review focused on executable trust-contract parity across CLI, installer, MCP, configuration, hostile environment input, and durable background-job completion. Maintainer memory was used only to direct inspection; each blocker above was independently confirmed from the snapshot or focused probes.
Test Coverage
tests/unit/test_telemetry.py: 20 passed.tests/unit/config/test_loader_env.py: 179 passed.tests/unit/scripts/test_install_runtime_selection.py: 29 passed.tests/unit/mcp/server/test_adapter.py: 64 passed, 5 skipped, and 10 failed because the review environment lacks the optionalmcppackage; failures were confined to SDK/serve tests requiring that extra.- Independent probes reproduced project
.envendpoint redirection and forced enablement, malformed-config fail-open behavior, and installer transmission despitetelemetry.enabled: false. - New tests exercise the telemetry module directly but do not cover installer opt-out/notice ordering, hostile project
.envkeys, malformed persisted config, adapter early-return failures, or durable background-job outcomes.
Merge Recommendation
Do not merge until telemetry control variables are protected from untrusted .env input, every persisted opt-out remains fail-closed across installer and malformed-config paths, notice precedes installer collection, and successful runs are measured at durable terminal verification rather than background-job submission. Add integration tests at each corrected boundary.
Review-Metadata:
verdict: REQUEST_CHANGES
head_sha: ee4d2c6
request_id: req_1785984259_616-retry-1
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
|
Broad direction review after the requested-changes loop: The bounded, asynchronous, failure-isolated telemetry foundation is a strong start, and the product-learning goal fits Ouroboros. The current trust and metric contracts do not yet fit the project direction, though:
Those behaviors conflict with the fail-closed local trust boundary and durable-evidence semantics. Please pause implementation and define one trusted telemetry-control resolver plus distinct submission and terminal-outcome events. Then prove opt-out, malformed-config, installer ordering, and failure-path behavior with integration tests. The existing queue and failure-isolation work should remain reusable once those contracts are explicit. |
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: REQUEST_CHANGES
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | ee4d2c6ffc319ea9eef4e3f622f9ad87e4e2226e |
| Request ID | req_1786109429_685 |
| Review record | 36ef418a-5c51-4706-9e0e-43b63774713f |
What Improved
- Adds a bounded, asynchronous, failure-isolated telemetry transport with no new runtime dependency.
- Centralizes MCP command instrumentation, samples high-frequency polling tools, and documents the proposed collection contract.
- Adds focused unit coverage for event shape, sampling, opt-out environment flags, identity persistence, first-run notice, and transport failures.
Issue Requirements
| Requirement | Status |
|---|---|
| Anonymous opt-out telemetry across supported runtimes | Partially met — collection exists, but project-controlled input can re-enable or redirect it and the installer ignores persisted opt-out. |
| Measure install and interview → seed → run → evolve funnels | Partially met — events exist, but run submission is conflated with verified completion. |
| Measure terminal-CLI versus in-agent entry ratio | Partially met — CLI/MCP sources and MCP serve events are separated, but the surrounding trust contract remains unsafe. |
| Measure per-backend success rates | Not met — queued jobs are reported as successes and pre-handler failures are omitted. |
| Instrument MCP through a single chokepoint | Partially met — normal handler outcomes are captured, but unknown-tool and security failures bypass instrumentation. |
| Sample polling tools at 1/50 with a reweighting property | Met. |
| Publish an event whitelist, usage policy, counting rule, anonymity floor, and changelog | Met as documentation, but the verified-success counting rule is not executable with the emitted events. |
| Provide a one-time first-run notice | Partially met — the Python CLI notice is persisted, but installer events are emitted before the installer notice. |
Honor DO_NOT_TRACK, OUROBOROS_TELEMETRY=0, and telemetry.enabled: false |
Not met across all surfaces and hostile/malformed inputs. |
| Keep telemetry asynchronous, bounded, non-blocking, and dependency-free | Met for the Python transport. |
| Use a random persistent UUID without machine fingerprinting | Met. |
| Remove telemetry identity during normal uninstall data cleanup | Met when ~/.ouroboros/ is removed; intentionally retained with --keep-data. |
Prior Findings Status
The prior trust-contract and durable-success concerns are maintained based on fresh current-snapshot evidence. No contributor response or current implementation change addresses the project .env authority, malformed-config fallback, installer ordering/opt-out, queued-versus-terminal success, or omitted early adapter failures.
Blockers
| # | File:Line | Severity | Finding |
|---|---|---|---|
| 1 | src/ouroboros/telemetry.py:99 | BLOCKING | Project-controlled .env files can re-enable and redirect telemetry. _api_key() and _host() trust OUROBOROS_POSTHOG_API_KEY and OUROBOROS_POSTHOG_HOST, while get_telemetry_enabled() trusts OUROBOROS_TELEMETRY; importing the config loader loads the current project's .env, and none of these keys are denied by UNTRUSTED_ENV_DENYLIST. A focused probe with a user config containing telemetry.enabled: false and a project .env containing OUROBOROS_TELEMETRY=1, an attacker host, and attacker key produced enabled=True and selected the attacker destination. Operator-owned telemetry controls and destination configuration must come only from trusted process/home sources, with regression tests for hostile project environments. |
| 2 | src/ouroboros/config/loader.py:1436 | BLOCKING | Any ConfigError, including malformed YAML or an unrelated invalid configuration field, falls back to telemetry enabled. A focused probe using a malformed ~/.ouroboros/config.yaml returned True. Because a privacy preference may be present but unreadable alongside the malformed content, this must fail closed rather than silently sending events. Add tests covering malformed YAML and unrelated validation errors. |
| 3 | scripts/install.sh:191 | BLOCKING | The installer sends install_started before displaying the telemetry notice and never reads the persisted telemetry.enabled setting. A focused installer probe with ~/.ouroboros/config.yaml containing telemetry.enabled: false still emitted both install_started and install_completed; the notice was printed only afterward at lines 703–704. The installer must resolve the same trusted opt-out contract as the Python surfaces and present the notice before its first collection attempt. |
| 4 | src/ouroboros/mcp/server/adapter.py:1026 | BLOCKING | ok=result.is_ok measures successful handler submission, not a successful verified run. For example, StartExecuteSeedHandler queues work and immediately returns Result.ok with a queued job at src/ouroboros/mcp/tools/execution_handlers.py:2862; durable completion or failure is recorded later by JobManager. No terminal-outcome telemetry exists, so failed background executions are currently counted as successful run funnel events, contradicting the documented weekly-active-user rule. Emit distinct submission and durable terminal-outcome events, and derive verified success only from terminal execution evidence. |
| 5 | src/ouroboros/mcp/server/adapter.py:970 | BLOCKING | The claimed single chokepoint omits failures that occur before handler invocation. Unknown tools return at line 987 and security rejections return at line 1001, both before capture_tool_call(). A focused call to an unknown ouroboros_* tool returned an error while the capture spy remained empty. This biases reliability and backend failure rates toward success. Instrument all adapter exits through one finalization path and add coverage for unknown-tool and security-denial outcomes. |
Follow-up Findings
| # | File:Line | Priority | Confidence | Suggestion |
|---|---|---|---|---|
| None. |
Non-blocking Suggestions
None.
Test Coverage Notes
tests/unit/test_telemetry.py: 20 passed.tests/unit/scripts/test_install_runtime_selection.py: 29 passed, but contains no assertions for installer telemetry notice, opt-out, destination, or emission ordering.- Config-loader and adapter run: 243 passed, 5 skipped, and 10 failed because the optional
mcppackage was not installed; the relevant non-SDK adapter tests otherwise executed. TestMCPServerAdapterTools: 12 passed and 1 unrelated optional-mcpdependency failure.- Focused probes independently reproduced project
.envre-enablement/redirection, malformed-config fail-open behavior, installer emission despite persisted opt-out, notice-after-emission ordering, and omitted unknown-tool failure telemetry.
Design Notes
The queue and boundary-oriented instrumentation are reusable, but telemetry authority and outcome semantics need a single trusted resolver plus durable terminal-event integration before the design is safe.
Design / Roadmap Gate
This change crosses persistent identity, installer, configuration, untrusted project environment, MCP security, and durable background-job boundaries. Current behavior permits destination redirection and opt-out override from a cloned repository, fails open when user configuration is malformed, emits installer events before notice, and lacks truthful terminal-success evidence. These violate the proposed telemetry contract and infrastructure trust model rather than representing optional metric refinements.
Directional Notes
Review focus followed the maintainer trust and replay-evidence posture: operator privacy controls must dominate project input, telemetry failures must remain non-blocking, and accepted or queued work must not be represented as verified terminal success. All blockers above are independently supported by the current snapshot and focused probes.
Test Coverage
tests/unit/test_telemetry.py: 20 passed.tests/unit/scripts/test_install_runtime_selection.py: 29 passed, but contains no assertions for installer telemetry notice, opt-out, destination, or emission ordering.- Config-loader and adapter run: 243 passed, 5 skipped, and 10 failed because the optional
mcppackage was not installed; the relevant non-SDK adapter tests otherwise executed. TestMCPServerAdapterTools: 12 passed and 1 unrelated optional-mcpdependency failure.- Focused probes independently reproduced project
.envre-enablement/redirection, malformed-config fail-open behavior, installer emission despite persisted opt-out, notice-after-emission ordering, and omitted unknown-tool failure telemetry.
Merge Recommendation
Do not merge until telemetry controls and destinations are resolved exclusively from trusted sources, malformed configuration fails closed, installer notice and opt-out checks precede collection, and separate submission plus durable terminal-outcome events provide complete failure accounting. Add integration tests for each corrected boundary.
Review-Metadata:
verdict: REQUEST_CHANGES
head_sha: ee4d2c6
request_id: req_1786109429_685
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
Remediation verification — exact HEAD
|
|
@ouroboros-agent please re-review exact HEAD 871c00c |
|
Resolved the two independently reproduced exact-HEAD blockers on Changes:
Verification:
No merge performed. @ouroboros-agent please re-review exact HEAD 96cf738 |
Independent exact-head re-verification — HOLD / FAILVerified HEAD: The two returned blockers are substantially fixed: terminal evaluation outcomes are truthful, and the installer now validates the full configuration fail-closed while preserving genuinely absent default-on plus notice-before-capture. A remaining privacy bypass is blocking. Blocker: dangling config symlink fails openBoth runtime surfaces treat a dangling
Reproduction:
Expected: this is invalid/unreadable configuration, not genuinely absent configuration, so both installer and Python collection must remain disabled. Use Other gate status
No approval or merge was performed. |
|
Resolved the dangling-config-symlink privacy bypass on exact HEAD Changes:
Verification:
I did not manually rerun or mask the separate #1933 lease-test flake. No approval or merge performed. @ouroboros-agent please re-review exact HEAD 28f2eee |
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: REQUEST_CHANGES
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | 28f2eee3e47c49e5eb477841158a024737ba37f9 |
| Request ID | req_1786129068_854 |
| Review record | ebc3c15c-f400-43c4-af85-31f066766aa2 |
What Improved
- Adds bounded, asynchronous, failure-isolated telemetry with centralized event serialization and an explicit public data contract.
- Separates asynchronous submission receipts from deduplicated durable terminal outcomes, requiring completed evaluation plus literal
final_approved=truefor verified success. - Protects telemetry controls from project-local
.env, handles dangling configuration symlinks fail-closed, samples polling tools, and captures MCP failures exactly once.
Issue Requirements
| Requirement | Status |
|---|---|
| Anonymous, opt-out PostHog telemetry across install, CLI, MCP, funnel, and backend surfaces | Partially met — instrumentation exists, but two declared persistent opt-out paths can be bypassed by installer/runtime precedence differences. |
| Single MCP chokepoint plus CLI and installer instrumentation | Met |
Polling tools sampled 1/50 with sample_rate weighting |
Met |
| Public trust contract with event whitelist, declared uses, fixed active-user rule, k-anonymity floor, and changelog | Met |
| Three complete opt-out paths with operator-owned control authority | Not met — explicit enable bypasses persisted opt-out/fail-closed configuration, and the installer ignores trusted ~/.ouroboros/.env. |
| One-time notice before first collection | Met for enabled paths covered by tests, including the standalone installer |
| Stdlib-only, bounded, non-blocking, failure-isolated transport | Met |
| Random UUID identity without machine fingerprinting or payload content | Met |
| Submission acceptance must not be reported as verified execution success | Met |
| Durable terminal outcomes and verified evaluation success must be truthful and deduplicated | Met |
Project-controlled .env must not control telemetry enablement, key, or destination |
Met |
Prior Findings Status
Most earlier trust and durability concerns are resolved in the current snapshot: project-local telemetry overrides are denied, ordinary malformed configuration and dangling symlinks fail closed, notice precedes installer capture, submissions are distinct from terminal outcomes, verified success requires truthful terminal evidence, and adapter failures are captured exactly once. The privacy-control concern is maintained in narrower form because current evidence shows explicit-enable precedence and the installer’s omission of trusted user .env still bypass declared operator opt-outs.
Blockers
| # | File:Line | Severity | Finding |
|---|---|---|---|
| 1 | src/ouroboros/config/loader.py:1458 | BLOCKING | OUROBOROS_TELEMETRY=1 returns True before inspecting persisted configuration, so it overrides both telemetry.enabled: false and malformed/unreadable configuration. The installer repeats this bypass at scripts/install.sh:193. I reproduced both Python and installer paths: with either a persisted opt-out or malformed YAML plus OUROBOROS_TELEMETRY=1, telemetry was enabled, the notice appeared, and both installer events were captured. This contradicts TELEMETRY.md:42 (“Any one … disables telemetry completely”), the fail-closed contract at TELEMETRY.md:62, and the contributor’s stated complete persisted opt-out. Resolve all disabling sources before accepting an explicit enable, and add runtime plus installer regressions for this precedence combination. |
| 2 | scripts/install.sh:98 | BLOCKING | The installer reads telemetry controls and destination only from its inherited process environment; unlike the application loader at src/ouroboros/config/loader.py:256, it never reads the trusted ~/.ouroboros/.env declared at TELEMETRY.md:59. I reproduced an installation with ~/.ouroboros/.env containing OUROBOROS_TELEMETRY=0: the installer still displayed the notice and emitted install_started and install_completed. A destination override in that file is likewise ignored, causing installer data to go to the embedded PostHog project while later application events use the operator-selected destination. Parse the allowlisted telemetry keys from the trusted user env file with real-process-environment precedence before any notice or capture, and cover opt-out and destination behavior in the copied-installer tests. |
Follow-up Findings
| # | File:Line | Priority | Confidence | Suggestion |
|---|---|---|---|---|
| None. |
Non-blocking Suggestions
| 1 | src/ouroboros/telemetry.py:403 | Documentation/Packaging | The first-run notices direct installed users to a bare TELEMETRY.md, but the built wheel does not contain that file and the installer is not retained after curl \| bash. Use a stable public URL in the notice or package and expose the document so users can actually inspect the detailed contract before later collection. |
Test Coverage Notes
- Ran the focused telemetry, configuration environment, MCP adapter, job-manager, and installer suites with
/root/.local/bin/uv:553 passed, 1 skipped. - Ruff lint and focused format checks passed;
bash -n scripts/install.shpassed. - Direct Python probes confirmed
OUROBOROS_TELEMETRY=1overrides both persistedfalseand malformed configuration. - Copied-installer probes confirmed the same override and confirmed that
~/.ouroboros/.envopt-out is ignored. - Built the wheel successfully and confirmed it contains no
TELEMETRY.md.
Design Notes
The centralized Python telemetry module and thin MCP boundary are well structured, and durable outcome observation is attached at the correct persistence boundary. The remaining architectural weakness is duplicated control resolution: Python and the standalone installer implement different trusted-source and precedence semantics.
Design / Roadmap Gate
The change crosses persistent identity, user configuration, trusted environment, installer, MCP, and durable job boundaries. Runtime outcome semantics, replay deduplication, failure isolation, and project-env compatibility now fit the infrastructure design. Merge remains blocked because the public “any one opt-out wins” contract is not consistently executable: explicit enable bypasses persisted state, and the installer omits one declared trusted persistent control source.
Directional Notes
Review focused on operator-owned privacy controls, fail-closed malformed state, truthful durable outcomes, and contract parity across installer, CLI, MCP, and background workers. Maintainer memory only guided those checks; both blockers were independently reproduced from the current snapshot.
Test Coverage
- Ran the focused telemetry, configuration environment, MCP adapter, job-manager, and installer suites with
/root/.local/bin/uv:553 passed, 1 skipped. - Ruff lint and focused format checks passed;
bash -n scripts/install.shpassed. - Direct Python probes confirmed
OUROBOROS_TELEMETRY=1overrides both persistedfalseand malformed configuration. - Copied-installer probes confirmed the same override and confirmed that
~/.ouroboros/.envopt-out is ignored. - Built the wheel successfully and confirmed it contains no
TELEMETRY.md.
Merge Recommendation
Do not merge until a single precedence contract is applied across Python and install.sh: persisted opt-out and invalid configuration must remain fail-closed even with OUROBOROS_TELEMETRY=1, and the installer must honor allowlisted telemetry controls from ~/.ouroboros/.env. Add focused regressions for both boundaries.
Review-Metadata:
verdict: REQUEST_CHANGES
head_sha: 28f2eee
request_id: req_1786129068_854
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
# Conflicts: # src/ouroboros/mcp/job_manager.py
…ller OUROBOROS_TELEMETRY=1 is no longer an override: get_telemetry_enabled() resolves every disabling source first (DO_NOT_TRACK, env=0, persisted telemetry.enabled: false, invalid/unreadable config), so an explicit enable can never defeat a persisted opt-out or fail-closed state. The installer applies the same rule and now reads the four allowlisted telemetry keys from trusted ~/.ouroboros/.env before its notice or first event, with real-process-environment precedence mirroring the loader. First-run notices now point at the canonical GitHub TELEMETRY.md URL since the wheel does not package the file. Regressions: explicit-enable vs persisted/malformed config on both the Python resolver and the copied installer, user-env opt-out, user-env destination override, and process-env precedence over the user env file. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@ouroboros-agent Both blockers from review Blocker 1 — explicit enable overriding persisted opt-out ( Blocker 2 — installer ignoring trusted Non-blocking suggestion: both first-run notices now point at the canonical GitHub URL for TELEMETRY.md instead of the bare filename, since the wheel does not package the file. Verification: telemetry + installer + loader-env suites 276 passed; MCP adapter + job-manager suites 298 passed; ruff lint/format clean; mypy clean on touched sources; |
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: REQUEST_CHANGES
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | d072f5c6a7f0d7d33126a9e30edbce318e07960f |
| Request ID | req_1786217700_1032 |
| Review record | aa625691-45d8-4728-9026-da24d2dec440 |
What Improved
- Adds centralized, sanitized telemetry instrumentation for CLI, MCP adapter, installer, and durable job outcomes.
- Separates asynchronous submission acceptance from terminal workflow outcomes and limits verified success to approved evaluations.
- Protects telemetry controls and destinations from project-local
.env, fails closed on invalid configuration, and samples polling tools.
Issue Requirements
| Requirement | Status |
|---|---|
| Anonymous, opt-out PostHog telemetry across installer, CLI, MCP, and runtime backends | Partially met — instrumentation exists, but the installer can bypass valid persisted opt-outs |
| Single MCP chokepoint plus CLI and installer instrumentation | Met |
| Polling tools sampled 1/50 with a reweighting property | Met |
| Three opt-out paths and consistent trusted-control precedence | Not met — quoted dotenv values with inline comments are not honored by the installer |
| One-time notice before first installer collection | Met for recognized configurations and controls |
| Fixed active-user rule based on verified terminal evaluation outcomes | Met |
| Asynchronous, failure-isolated transport that never blocks commands | Not met — the atexit flush adds a bounded but material synchronous exit delay |
| Random UUID identity with no machine fingerprinting or content collection | Met |
| MCP serve attachment denominator separated from direct terminal usage | Met |
Prior Findings Status
The earlier explicit-enable precedence blocker is resolved: persisted opt-out, malformed configuration, and DO_NOT_TRACK now dominate OUROBOROS_TELEMETRY=1. Malformed/unreadable configuration, dangling symlinks, notice ordering, and durable terminal-outcome semantics also verify as corrected. The trusted ~/.ouroboros/.env concern is modified rather than withdrawn: the source is now read, but its hand-written parser still bypasses valid dotenv opt-outs containing quoted values followed by comments.
Blockers
| # | File:Line | Severity | Finding |
|---|---|---|---|
| 1 | scripts/install.sh:121 | BLOCKING | The installer’s trusted ~/.ouroboros/.env parser does not match the application’s python-dotenv semantics. A normal dotenv entry such as OUROBOROS_TELEMETRY="0" # persisted opt-out does not end with a quote, so it enters the unquoted branch and retains the quotes around 0; _telemetry_enabled then fails to recognize the opt-out and emits the notice and both install events. DO_NOT_TRACK="1" # off fails identically. I reproduced collection for both forms. This violates the documented guarantee that the installer honors the same trusted persistent controls as the Python resolver. Use a dotenv-compatible parser or correctly handle quoted values followed by comments, with regressions for both opt-out variables. |
Follow-up Findings
src/ouroboros/telemetry.py:265[warning] Registeringflush()withatexitmakes short commands synchronously wait up to 1.5 seconds for telemetry, while_post()itself may remain blocked for the four-second HTTP timeout. A stalled fake transport increased a trivial process from approximately 0.17 seconds to 2.03 seconds. Therefore the daemon queue does not satisfy the PR’s public “telemetry never blocks a command” contract and can noticeably delay every short CLI invocation when PostHog or an operator-configured destination is unreachable. Remove the blocking exit flush or redesign delivery so process termination remains effectively non-blocking, and add a stalled-transport latency regression.
| # | File:Line | Priority | Confidence | Suggestion |
|---|-----------|----------|------------|------------|
None.
Non-blocking Suggestions
| 1 | src/ouroboros/telemetry.py:37 | Documentation | The comment says an empty API key disables telemetry, but _api_key() at line 125 replaces an empty environment value with the embedded key. Either correct the comment or implement the stated behavior to avoid misleading future maintainers. |
Test Coverage Notes
531 passedfor telemetry, loader environment, MCP adapter, and job-manager suites usinguv --extra mcp.42 passed, 1 skippedfor the installer runtime-selection suite.- Ruff checks and
bash -n scripts/install.shpassed. - Additional focused probes reproduced the quoted-inline-comment opt-out bypass and the approximately 1.5-second exit wait under a stalled telemetry transport; neither path is covered by the authored tests.
Design Notes
The adapter observer and durable job boundary are appropriately separated from MCP business logic, and the event semantics are substantially improved. The remaining failures are boundary-contract issues in installer parsing and process lifecycle behavior, not architectural objections to telemetry itself.
Design / Roadmap Gate
The PR crosses trusted environment, persistent identity, installer, CLI lifecycle, MCP, and durable-job boundaries. Durable outcome truthfulness, project-env destination protection, replay deduplication, and malformed-config handling now fit the infrastructure contract. Merge remains blocked because the installer still interprets one trusted control source differently from the application, and the exit lifecycle contradicts the declared non-blocking transport guarantee.
Directional Notes
Review focus followed the maintainer trust posture: operator privacy controls must remain authoritative across every entry surface, and advertised asynchronous instrumentation must not degrade command execution. Prior memory guided inspection only; both blockers were independently reproduced from the current snapshot.
Test Coverage
531 passedfor telemetry, loader environment, MCP adapter, and job-manager suites usinguv --extra mcp.42 passed, 1 skippedfor the installer runtime-selection suite.- Ruff checks and
bash -n scripts/install.shpassed. - Additional focused probes reproduced the quoted-inline-comment opt-out bypass and the approximately 1.5-second exit wait under a stalled telemetry transport; neither path is covered by the authored tests.
Merge Recommendation
Do not merge until the installer accepts the same quoted/commented dotenv opt-outs as the Python loader and telemetry cannot delay process exit under a stalled destination. Add focused regressions for both corrected boundaries.
Review-Metadata:
verdict: REQUEST_CHANGES
head_sha: d072f5c
request_id: req_1786217700_1032
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
# Conflicts: # src/ouroboros/cli/commands/mcp.py
…lock process exit Two review blockers from the ouroboros-agent round on d072f5c: - scripts/install.sh: the hand-rolled ~/.ouroboros/.env parser only stripped quotes when the raw value ended with one, so a normal python-dotenv entry like OUROBOROS_TELEMETRY="0" # persisted opt-out fell into the unquoted branch, kept its quotes, and the opt-out was ignored. Quoted values now run to the first matching close quote with only whitespace/comment allowed after it; unclosed quotes and trailing garbage skip the binding, matching python-dotenv parse-error semantics. - src/ouroboros/telemetry.py: drop the atexit-registered flush(). It made every short CLI command wait up to 1.5s at exit when the destination stalled, contradicting the documented never-blocks contract. The worker stays a daemon thread; events still queued at process exit are dropped, and flush() remains available for explicit callers. Docs updated. Regressions: quoted/single-quoted/commented opt-outs for both OUROBOROS_TELEMETRY and DO_NOT_TRACK, unclosed-quote and trailing-garbage binding skips, and a stalled-transport subprocess exit-latency bound. Also corrects the embedded-API-key comment to describe the real fallback. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013YX7oZyy92gYdoGKavaNQw
|
@ouroboros-agent Both blockers from round req_1786217700_1032 are addressed in 8d418f5 (plus a main merge for the conflict): 1. Installer dotenv parser (scripts/install.sh) — fixed. Quoted values now follow python-dotenv semantics: the value runs to the first matching closing quote, and only whitespace and/or a 2. Blocking exit flush (src/ouroboros/telemetry.py) — removed. 3. Non-blocking suggestion — comment corrected. The embedded-key comment now says an empty constant (e.g. stripped in a fork) disables telemetry, while a blank/unset Verification: |
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: REQUEST_CHANGES
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | 8d418f597719edc1738061376cd7a819e4823512 |
| Request ID | req_1786309679_1218 |
| Review record | 2dd6192e-7e8d-4ed8-bae8-916027dbb81b |
What Improved
- Adds bounded, failure-isolated telemetry transport with documented event and privacy contracts.
- Separates asynchronous submission receipts from durable workflow outcomes and records adapter failures exactly once.
- Protects telemetry controls and destinations from project-controlled
.envvalues, fails closed on invalid configuration, and removes exit-time flushing.
Issue Requirements
| Requirement | Status |
|---|---|
| Provide anonymous opt-out usage telemetry across supported runtimes | Partially met — instrumentation exists, but installer opt-out parity remains incomplete. |
| Instrument MCP calls through a shared boundary plus direct CLI and installer entrypoints | Met |
| Sample high-frequency polling tools at 1/50 with a reweighting property | Met |
| Ship a documented trust contract, first-run notice, and three authoritative opt-out paths | Partially met — documented trusted .env forms accepted by the application can still be ignored by the installer. |
| Keep transport bounded, asynchronous, failure-isolated, and non-blocking at process exit | Met |
Use one stable random UUID stored in ~/.ouroboros/telemetry.json |
Not met — concurrent first use can produce multiple IDs. |
| Distinguish accepted asynchronous submissions from verified durable outcomes | Met |
Prevent project-controlled .env files from changing telemetry authority or destination |
Met |
Prior Findings Status
Prior blockers concerning project .env authority, malformed configuration, installer notice ordering, submission-versus-terminal semantics, quoted/commented opt-outs, and exit-time blocking are withdrawn based on the current snapshot and passing regressions. The two blockers above are newly verified remaining failures in the same trust and identity contracts.
Blockers
| # | File:Line | Severity | Finding |
|---|---|---|---|
| 1 | scripts/install.sh:111 | BLOCKING | The installer still does not honor the same trusted ~/.ouroboros/.env opt-outs as the Python loader. Its hand-written parser recognizes only the literal prefix export , so valid python-dotenv forms such as export OUROBOROS_TELEMETRY=0 or a tab after export are skipped. The flag checks at lines 266–267 are also only partially case-insensitive: values such as OUROBOROS_TELEMETRY=OFF and DO_NOT_TRACK=YES disable application telemetry but not installer telemetry. Focused installer probes confirmed all four forms display the notice and emit install events. This violates the documented “any one opt-out wins” and cross-runtime parity contract. Normalize the full accepted grammar and flag casing, with installer regressions for each form. |
Follow-up Findings
src/ouroboros/telemetry.py:164[warning] First-use identity creation is protected only by a process-local lock. Concurrent processes can both observe a missing state file, generate different UUIDs, overwritetelemetry.json, and retain different IDs in their process caches. A synchronized 64-process probe returned multiple distinct IDs while only one survived in the file. Concurrent MCP sessions or installer/application startup can therefore count one installation as multiple active users and violate the stated stable-identity contract. Use cross-process atomic creation or locking, then reload the winning state before caching it; coordinate the installer writer with the same protocol and add concurrent creation tests.
| # | File:Line | Priority | Confidence | Suggestion |
|---|-----------|----------|------------|------------|
None.
Non-blocking Suggestions
| 1 | tests/unit/test_telemetry.py:404 | Test hygiene | The stalled-transport regression passes but produces PytestUnhandledThreadExceptionWarning because the acceptor thread calls accept() after the socket is closed. Catch the shutdown OSError or stop and join the thread before closing the socket so telemetry tests remain warning-clean. |
Test Coverage Notes
- Ran
SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0 /root/.local/bin/uv run --extra mcp python -m pytest -q tests/unit/test_telemetry.py tests/unit/config/test_loader_env.py tests/unit/mcp/server/test_adapter.py tests/unit/mcp/test_job_manager.py tests/unit/scripts/test_install_runtime_selection.py: 584 passed, 1 skipped, 1 warning. - Focused installer probes reproduced collection for valid trusted-env opt-outs using multiple-space/tab
export,OFF, andYES. - A synchronized 64-process identity probe reproduced multiple UUIDs from one initially absent
telemetry.json.
Design Notes
The telemetry boundary is appropriately thin, and durable outcome instrumentation fits the event-driven architecture. The remaining issues are cross-entrypoint trust parity and atomic ownership of persistent identity, both foundational to truthful metrics.
Design / Roadmap Gate
The changed boundary spans installer parsing, trusted environment configuration, persistent identity, MCP request observation, and durable job completion. Request and outcome semantics now preserve submission/completion distinctions and replay deduplication. Merge remains blocked because valid persisted opt-outs are still interpreted differently by the installer and application, while identity persistence is not atomic across the concurrent processes expected in multi-agent/MCP use.
Directional Notes
Review focus followed the advisory trust posture: operator opt-outs must dominate every entry surface, and published adoption metrics require a genuinely stable identity. Both blockers are grounded in current-source probes rather than prior review or memory claims.
Test Coverage
- Ran
SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0 /root/.local/bin/uv run --extra mcp python -m pytest -q tests/unit/test_telemetry.py tests/unit/config/test_loader_env.py tests/unit/mcp/server/test_adapter.py tests/unit/mcp/test_job_manager.py tests/unit/scripts/test_install_runtime_selection.py: 584 passed, 1 skipped, 1 warning. - Focused installer probes reproduced collection for valid trusted-env opt-outs using multiple-space/tab
export,OFF, andYES. - A synchronized 64-process identity probe reproduced multiple UUIDs from one initially absent
telemetry.json.
Merge Recommendation
Do not merge until installer opt-out resolution matches the Python loader for all accepted trusted-env forms and telemetry identity creation is atomic across processes and the installer. Add focused regressions for both boundaries; the existing telemetry and durable-outcome foundation can otherwise remain.
Review-Metadata:
verdict: REQUEST_CHANGES
head_sha: 8d418f5
request_id: req_1786309679_1218
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
…mic identity creation Second review round on 8d418f5: - scripts/install.sh: accept `export` followed by any run of whitespace (not just a single space) in the trusted ~/.ouroboros/.env parser, and lowercase+trim flag values before matching so OUROBOROS_TELEMETRY=OFF / DO_NOT_TRACK=YES disable installer telemetry exactly like the application resolver's .strip().lower() sets. - Identity creation is now atomic across processes on both surfaces: telemetry.py publishes a fresh telemetry.json via same-dir temp file + os.link (create-if-not-exists), falls back to O_CREAT|O_EXCL where hard links are unsupported, then re-reads and adopts whichever distinct_id actually won; install.sh uses the same tmp + ln publish and re-reads the winner. Concurrent first use can no longer mint diverging UUIDs. - Stalled-transport regression no longer leaks a thread exception: the acceptor catches shutdown OSError and is joined before the socket closes. Regressions: multi-space/tab export forms, uppercase OFF/YES flags, export+quoted+comment combination, and a 16-process synchronized concurrent-identity test asserting one converged UUID. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013YX7oZyy92gYdoGKavaNQw
|
@ouroboros-agent Both findings from round req_1786309679_1218 are addressed in a8bb826: 1. Installer opt-out grammar/casing parity (scripts/install.sh) — fixed. The trusted-env parser now accepts 2. Concurrent first-use identity (src/ouroboros/telemetry.py) — made atomic on both surfaces. Python: 3. Test-hygiene suggestion — fixed. The stalled-transport acceptor now catches shutdown Verification: telemetry + loader-env + adapter + job-manager suites 533 passed, installer suite 58 passed, ruff check/format clean, |
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: REQUEST_CHANGES
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | a8bb826d91ad760a16815e5a4b5802b18b85a383 |
| Request ID | req_1786311128_1225 |
| Review record | e0dd3f24-241c-436f-94c9-5bc78640410f |
What Improved
- Adds bounded, daemon-thread telemetry transport with failure isolation and no exit-time flush.
- Establishes operator-owned opt-out precedence across process environment, trusted user environment, persisted configuration, installer, CLI, and MCP paths.
- Separates asynchronous submission receipts from durable terminal outcomes and requires explicit evaluation approval for verified success.
- Adds atomic first-use identity publication, MCP failure-boundary instrumentation, polling sampling, first-run disclosure, and extensive regression coverage.
Issue Requirements
| Requirement | Status |
|---|---|
| Anonymous opt-out telemetry for install, funnel conversion, entry-surface ratios, and backend outcomes | Partially met — instrumentation exists, but unrestricted serialization can violate the anonymity contract and corrupt identity state makes user-level metrics unreliable. |
| Single MCP request chokepoint plus CLI and installer instrumentation | Met — adapter, SDK, CLI, serve, installer, and durable-job boundaries were traced and covered by targeted tests. |
| Polling tools sampled 1/50 with a reweighting property | Met |
| Event whitelist that excludes code, prompts, file contents, paths, arguments, and environment variables | Not met — capture() and set_context() enforce no event or property allowlist. |
| Fixed verified weekly-active-user counting rule with installs, submissions, retries, and CI excluded | Partially met — durable outcome semantics and CI marking are implemented, but malformed state causes one installation to generate multiple anonymous identities. |
| Three authoritative opt-out paths, including fail-closed malformed configuration | Met |
| Installer honors trusted persistent controls and shows/persists notice before collection | Met |
| Stdlib-only, bounded, failure-isolated, non-blocking transport | Met |
Stable random UUID identity in ~/.ouroboros/telemetry.json |
Not met — malformed existing state is never repaired and produces a new unpersisted UUID per process. |
| MCP serve attachment denominator without inflating direct terminal-CLI usage | Met |
| In-process automation and detached workers do not inflate MCP request ratios | Met |
| Telemetry disabled suite-wide with isolated fake-transport tests | Met |
Prior Findings Status
The specific prior blockers around trusted dotenv parsing, flag casing/grammar parity, blocking exit flush, absent-file concurrent identity creation, and stalled-test-thread cleanup are withdrawn: current source and focused tests show those changes are present. The earlier classification standard remains applicable—privacy declarations must be enforced at runtime and identity must remain stable across persistent-state failure. Applying that standard to current HEAD reveals the new allowlist-enforcement and malformed-state-repair blockers above.
Blockers
| # | File:Line | Severity | Finding |
|---|---|---|---|
| 1 | src/ouroboros/telemetry.py:358 | BLOCKING | Enforce the documented event and property whitelist at the serialization boundary. capture() accepts any event name and forwards every caller-provided property unchanged, while set_context() similarly accepts unrestricted global properties; both are exposed through the module's public exports. A focused fake-transport probe successfully emitted not_whitelisted with prompt and file_path properties, directly contradicting the PR's event-whitelist requirement and TELEMETRY.md's promise that serialization uses allowlisted properties and can never collect prompts or paths. Auditing today's call sites does not make that privacy contract executable; reject unknown events/properties or construct each supported event from a fixed schema before queueing it. |
| 2 | src/ouroboros/telemetry.py:159 | BLOCKING | Repair malformed identity state instead of minting an unpersisted UUID. When telemetry.json exists but cannot be decoded, _load_state() generates a candidate, but _publish_new_state() only uses create-if-absent operations; both os.link() and O_EXCL refuse the existing corrupt file, the rereads fail, and the local candidate is returned without replacing the file. I reproduced two fresh processes against one corrupt file returning different UUIDs while the file remained unchanged. This permanently fragments the promised stable identity and corrupts retention/weekly-active metrics; _write_state() also uses a non-atomic truncate-and-write, so interruption can create this state internally. Atomically replace invalid state, make subsequent state updates atomic, and test stability across process reloads after corruption. |
Follow-up Findings
| # | File:Line | Priority | Confidence | Suggestion |
|---|---|---|---|---|
| 1 | src/ouroboros/telemetry.py:484 | Medium | High | Consider making the notice check-and-set cross-process atomic. Concurrent first-use CLI/MCP processes can all read notice_shown=false and each display the advertised one-time notice before independently writing true. This does not expose data because each process discloses before capture, but it can produce repeated notices during simultaneous agent-session startup. |
Non-blocking Suggestions
None.
Test Coverage Notes
- Ran
SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0 /root/.local/bin/uv run --extra mcp python -m pytest -q tests/unit/test_telemetry.py tests/unit/config/test_loader_env.py tests/unit/mcp/server/test_adapter.py tests/unit/mcp/test_job_manager.py tests/unit/scripts/test_install_runtime_selection.py: 590 passed, 1 skipped. - Ran Ruff against the changed telemetry, configuration, MCP, installer-test, and telemetry-test surfaces: all checks passed.
- Installer syntax is exercised by the targeted installer suite.
- Independently reproduced permanent identity churn from malformed persisted state.
- Independently demonstrated that unrestricted event names, prompts, and file paths pass through
capture()to the transport. - No full repository test suite was run.
Design Notes
The request/outcome separation, trusted-control precedence, and thin MCP observation boundary now fit Ouroboros's infrastructure design. The remaining problems are both SSOT failures: privacy policy is documented but not enforced by the serializer, and identity persistence has no authoritative recovery path for invalid durable state.
Design / Roadmap Gate
This PR crosses persistent identity, trusted and untrusted environment loading, installer disclosure, CLI lifecycle, MCP request handling, and durable job-terminal boundaries. Opt-out precedence, submission-versus-terminal semantics, failure isolation, replay deduplication, and absent-state concurrent creation now satisfy the intended contracts. Merge remains blocked because the transport accepts data categories explicitly forbidden by the public contract and the identity state machine cannot recover from malformed durable state, allowing permanent metric fragmentation.
Directional Notes
Review focused on the maintainer trust posture: operator privacy controls must dominate project input, public telemetry declarations must match executable behavior, and published success/adoption metrics require durable terminal evidence plus a stable identity. Maintainer memory and prior reviews guided inspection only; both blockers were independently reproduced from the current snapshot.
Test Coverage
- Ran
SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0 /root/.local/bin/uv run --extra mcp python -m pytest -q tests/unit/test_telemetry.py tests/unit/config/test_loader_env.py tests/unit/mcp/server/test_adapter.py tests/unit/mcp/test_job_manager.py tests/unit/scripts/test_install_runtime_selection.py: 590 passed, 1 skipped. - Ran Ruff against the changed telemetry, configuration, MCP, installer-test, and telemetry-test surfaces: all checks passed.
- Installer syntax is exercised by the targeted installer suite.
- Independently reproduced permanent identity churn from malformed persisted state.
- Independently demonstrated that unrestricted event names, prompts, and file paths pass through
capture()to the transport. - No full repository test suite was run.
Merge Recommendation
Do not merge until telemetry events and properties are schema-allowlisted before queueing, and malformed or interrupted identity state is atomically repaired to one stable persisted UUID. Add regressions proving forbidden fields cannot reach the transport and repeated/concurrent processes converge after a corrupt state file.
Review-Metadata:
verdict: REQUEST_CHANGES
head_sha: a8bb826
request_id: req_1786311128_1225
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
…r corrupt identity state Third review round on a8bb826: - telemetry.py: capture() now drops any event not in _EVENT_ALLOWLIST and strips properties that are not allowlisted for that event (plus base and context keys), non-scalar, or longer than 200 chars; set_context() only accepts the four resolved-backend keys. TELEMETRY.md's whitelist is now executable at the serialization boundary instead of an audit promise. - telemetry.py: a telemetry.json that exists but is unparseable is now atomically repaired instead of wedging every process into a fresh unpersisted UUID: _write_state goes through tmp + os.replace, absent vs invalid files are distinguished, and invalid state is replaced under an O_EXCL repair lock with losers adopting the survivor (bounded waits, never raises). install.sh mirrors the absent-vs-corrupt distinction: ln create-if-absent, mv atomic repair, re-read-and-adopt either way. - show_first_run_notice() claims an O_EXCL marker so simultaneous first-use processes print the one-time notice exactly once. Regressions: forbidden events/properties never reach the transport, sequential and 8-process concurrent convergence after corruption, installer repair persisting events under the repaired id, single-notice race test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013YX7oZyy92gYdoGKavaNQw
|
@ouroboros-agent Both blockers from round req_1786311128_1225 are addressed in 2b786fc: 1. Event/property whitelist enforced at serialization (src/ouroboros/telemetry.py) — fixed. 2. Malformed identity state atomically repaired — fixed on both surfaces. 3. Medium follow-up (repeated notices) — fixed. Verification: telemetry + loader-env + adapter + job-manager suites 541 passed under |
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: REQUEST_CHANGES
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | 2b786fc84028d8e1622736715a9825b3f96bea67 |
| Request ID | req_1786312333_1233 |
| Review record | 13ce810f-35ef-4c2d-9715-4a3de51c115c |
What Improved
- Adds a centralized, bounded, failure-isolated telemetry transport with event/property allowlists.
- Protects telemetry controls and destinations from project-local
.envinput and fails closed on invalid user configuration. - Separates asynchronous submission receipts from durable terminal outcomes and only marks explicitly approved evaluations as verified.
- Adds broad regression coverage for opt-out precedence, installer disclosure, adapter failures, job outcomes, identity creation, and malformed state.
Issue Requirements
| Requirement | Status |
|---|---|
| Anonymous opt-out telemetry for installation, funnel conversion, entry-surface ratios, and backend success rates | Partially met — instrumentation exists, but stable identity and terminal-outcome delivery remain unreliable |
| Cover all supported runtime entry surfaces through the MCP chokepoint plus CLI and installer instrumentation | Met |
| Sample high-frequency polling tools at 1/50 with a re-weighting property | Met |
| Ship a truthful privacy contract, first-run notice, and three authoritative opt-out paths | Partially met — controls are substantially aligned, but a stale notice claim permits collection without completed disclosure |
| Use a stdlib-only, bounded, asynchronous transport that never blocks command execution | Met |
| Persist one stable random anonymous UUID across sessions | Not met — concurrent installer repair of corrupt state can emit and persist different identities |
| Keep MCP serve attachments and internal automation from inflating terminal-versus-agent usage ratios | Met |
| Distinguish accepted asynchronous submissions from verified durable terminal outcomes | Partially met — event semantics are correct, but detached-worker exit can drop the durable outcome before transport |
| Exclude installs, retries, and CI from the published active-user counting rule | Partially met — the declared predicate is implemented, but missing terminal delivery and split identities make the resulting count unreliable |
Prior Findings Status
The prior event/property-whitelist blocker is resolved in current source. Malformed Python identity state is now atomically repaired, but the prior stable-identity concern is modified rather than withdrawn because the installer’s corrupt-state repair still permits concurrent identity splitting. The stale notice marker and detached-worker terminal-delivery issues are newly established from current-source evidence.
Blockers
| # | File:Line | Severity | Finding |
|---|---|---|---|
| 1 | scripts/install.sh:323 | BLOCKING | Corrupt identity repair is still not concurrency-safe in the installer. Every process that initially sees an invalid telemetry.json sets file_existed=true and later performs an unconditional mv of its own UUID before immediately adopting the current file. Concurrent repairers can therefore each emit under a different ID while the last writer becomes the persisted identity. A deterministic two-process probe against this snapshot returned IDs ending in ...001 and ...002, with ...002 persisted. This fragments the stable identity and active-user metrics. Use the same exclusive repair ownership/adopt-winner protocol across Python and the installer, and add a concurrent corrupt-state installer/cross-surface regression. |
| 2 | src/ouroboros/telemetry.py:692 | BLOCKING | The exclusive notice marker has no crash/staleness recovery. If a process creates telemetry.notice and terminates before setting notice_shown and printing, every later process returns on FileExistsError, while telemetry remains enabled and collection proceeds without disclosure. This was reproduced by creating the reachable post-crash state (notice_shown=false plus an existing marker): show_first_run_notice() printed nothing and left the flag false. The notice claim must be recoverable or atomically tied to completed disclosure, with a crash-state regression. |
| 3 | src/ouroboros/telemetry.py:519 | BLOCKING | The only event qualifying a user under the published counting rule is emitted from JobManager._append_event, but it is merely queued to a daemon thread. A detached worker returns after observing the terminal row at src/ouroboros/mcp/detached_worker.py:251 and never calls flush; the telemetry contract explicitly says queued or in-flight events are dropped at process exit. If the job task has already released, the worker has no grace period for DNS/TLS/HTTP completion, so terminal outcomes can be systematically lost even though submission events from the long-lived MCP parent survive. Add a bounded worker-local delivery handoff/flush after durable terminalization and an integration test that verifies a detached worker actually transports workflow_outcome before exit. |
Follow-up Findings
| # | File:Line | Priority | Confidence | Suggestion |
|---|---|---|---|---|
| None. |
Non-blocking Suggestions
None.
Test Coverage Notes
- Dependency-complete focused suite passed:
599 passed, 1 skippedacross telemetry, installer, config loader, MCP adapter, and job-manager tests usinguv run --extra mcp. - Focused identity/notice/outcome regressions passed:
5 passed. ruff checkpassed for changed Python paths, andbash -n scripts/install.shpassed.- Independent probes reproduced concurrent installer identity divergence and the stale-marker disclosure failure.
- Existing tests cover concurrent Python identity creation and a single installer repair, but not concurrent corrupt-state installer/cross-surface repair, notice-claim crash recovery, or terminal-event transport from a detached worker.
Design Notes
The telemetry policy boundary is now appropriately centralized and sanitized, and durable outcome semantics are much clearer. The remaining defects are state-machine and process-lifecycle failures at installer concurrency, disclosure recovery, and detached-worker delivery boundaries.
Design / Roadmap Gate
This PR crosses trusted environment loading, persistent identity, installer execution, CLI disclosure, MCP request handling, and durable job completion. Configuration precedence, schema allowlisting, submission-versus-outcome semantics, and Python absent-state creation now fit the intended architecture. Merge remains blocked because corrupt identity repair is not one cross-runtime transaction, the disclosure marker has an unrecoverable intermediate state, and detached terminal producers do not guarantee a bounded delivery opportunity for the event that defines verified active usage.
Directional Notes
Review focus followed the maintainer trust posture: operator disclosure and opt-outs must survive failure paths, published adoption metrics require a stable identity, and verified outcomes must reach telemetry from the runtime that produces them. Prior memory and earlier classifications guided inspection only; each blocker was independently verified from the current snapshot or a focused probe.
Test Coverage
- Dependency-complete focused suite passed:
599 passed, 1 skippedacross telemetry, installer, config loader, MCP adapter, and job-manager tests usinguv run --extra mcp. - Focused identity/notice/outcome regressions passed:
5 passed. ruff checkpassed for changed Python paths, andbash -n scripts/install.shpassed.- Independent probes reproduced concurrent installer identity divergence and the stale-marker disclosure failure.
- Existing tests cover concurrent Python identity creation and a single installer repair, but not concurrent corrupt-state installer/cross-surface repair, notice-claim crash recovery, or terminal-event transport from a detached worker.
Merge Recommendation
Do not merge until concurrent corrupt-state repair converges across installer and Python processes, notice claims recover safely after interruption, and detached workers provide tested bounded delivery of durable terminal outcomes. The focused suite is green, but it does not exercise these critical failure boundaries.
Review-Metadata:
verdict: REQUEST_CHANGES
head_sha: 2b786fc
request_id: req_1786312333_1233
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
|
@ouroboros-agent The error-taxonomy blocker from round req_1786326905_1382 is addressed in dda0ca1: Closed output vocabulary, no provenance trust (src/ouroboros/mcp/telemetry_boundary.py). Total failure isolation. The helper is wrapped in try/except returning Regressions (typed + SDK + direct-unit): spoofed Verification: adapter + evaluate-telemetry + telemetry suites 296 passed under |
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: REQUEST_CHANGES
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | dda0ca15953d578fc1ee2037070c39935253ed0b |
| Request ID | req_1786328585_1387 |
| Review record | 7d3bcdc4-8b8e-4eac-841f-c4028463e208 |
What Improved
- Adds bounded, failure-isolated telemetry transport with strict per-event property allowlists.
- Establishes operator-owned opt-out precedence across configuration, trusted environment, and installer paths.
- Separates asynchronous submission receipts from durable terminal outcomes and verified evaluation success.
- Sanitizes MCP tool names, job types, and error classifications at extension boundaries.
- Adds extensive regression coverage for identity persistence, replay deduplication, installer ordering, adapters, and job outcomes.
Issue Requirements
| Requirement | Status |
|---|---|
| Add anonymous PostHog usage telemetry for install, CLI/MCP funnel, and backend reliability measurement | Met |
| Cover shared MCP, direct CLI, and installer entry surfaces with polling sampled 1/50 | Met |
Provide three authoritative opt-out paths and prevent project .env from controlling telemetry |
Met |
| Never collect values that identify a user or project | Not met — dynamic installed-plugin names are serialized as CLI commands |
| Count active users only from non-CI, explicitly verified evaluation terminal outcomes | Met |
| Distinguish asynchronous submission acceptance from durable terminal success | Met |
| Use a random durable UUID rather than machine fingerprinting | Met |
| Keep transport bounded, asynchronous, non-blocking, and failure-isolated | Met |
| Display and persist a one-time first-run notice before collection | Met |
| Document the exact event/property whitelist and public aggregate-statistics policy | Partially met — the documented privacy exclusion does not match dynamic CLI behavior |
Prior Findings Status
The prior error-taxonomy and hostile-object concern is withdrawn: current source uses a closed error-name vocabulary and failure-isolated logical-error access, with focused tests passing. The overall request-changes posture remains, but for a newly verified cross-entrypoint gap: MCP extension names are normalized while dynamic CLI plugin names are still transmitted verbatim.
Blockers
| # | File:Line | Severity | Finding |
|---|---|---|---|
| 1 | src/ouroboros/cli/main.py:181 | BLOCKING | The new CLI chokepoint forwards ctx.invoked_subcommand directly to telemetry, but _PluginAwareGroup resolves arbitrary installed plugin names as top-level commands. capture_cli_command() then serializes that name verbatim at src/ouroboros/telemetry.py:1049, unlike the audited MCP extension mapping. I reproduced a successful dynamic command named acme-private-project producing command: "acme-private-project" in the queued PostHog event. Plugin namespaces commonly identify organizations or projects, violating TELEMETRY.md’s promise that identifying project data is never collected. Map dynamic plugin commands to a fixed value such as extension_command, permit verbatim names only from an audited built-in CLI set, and add an actual Click dynamic-dispatch regression. |
Follow-up Findings
| # | File:Line | Priority | Confidence | Suggestion |
|---|---|---|---|---|
| None. |
Non-blocking Suggestions
None.
Test Coverage Notes
- Reviewed telemetry, configuration, adapter, job-manager, detached-worker, evaluation-chain, and installer tests.
SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0 /root/.local/bin/uv run --extra mcp python -m pytest ...completed with792 passed, 8 skipped.- An initial run without the
mcpextra had 10 dependency-related adapter failures; all passed when rerun with the declared extra. - Focused Click and queue probes independently reproduced the untested dynamic-plugin command disclosure.
Design Notes
The centralized transport, durable-outcome boundary, opt-out resolver, and MCP metadata normalization are sound. CLI instrumentation needs the same closed-vocabulary treatment already applied to MCP tools and background job types.
Design / Roadmap Gate
This PR crosses persistent identity, trusted configuration, installer disclosure, MCP extension registration, dynamic CLI plugin dispatch, and durable terminal-state boundaries. Replay deduplication, opt-out precedence, outcome semantics, and MCP extension sanitization now fit the intended trust model. Merge remains blocked because the CLI side of the same public extension contract lacks canonicalization and can disclose plugin-controlled identifiers contrary to the published privacy contract.
Directional Notes
Review focused on executable privacy parity across CLI, plugin, MCP, installer, configuration, and durable job paths. Maintainer memory guided attention toward operator-owned opt-outs and truthful outcomes, but the blocker is independently established from current source and runtime probes.
Test Coverage
- Reviewed telemetry, configuration, adapter, job-manager, detached-worker, evaluation-chain, and installer tests.
SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0 /root/.local/bin/uv run --extra mcp python -m pytest ...completed with792 passed, 8 skipped.- An initial run without the
mcpextra had 10 dependency-related adapter failures; all passed when rerun with the declared extra. - Focused Click and queue probes independently reproduced the untested dynamic-plugin command disclosure.
Merge Recommendation
Do not merge until dynamic plugin CLI commands are represented by a fixed non-identifying category and a Click-level regression proves plugin names cannot reach serialized telemetry. The focused implementation suites otherwise pass.
Review-Metadata:
verdict: REQUEST_CHANGES
head_sha: dda0ca1
request_id: req_1786328585_1387
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
Fifteenth review round on dda0ca1: - telemetry.py: capture_cli_command serializes a subcommand verbatim only when it belongs to _CANONICAL_CLI_COMMANDS -- the 27 statically registered built-in ooo subcommands enumerated from the real typer app (including the hidden monitor/dispatch aliases). Anything resolved dynamically by _PluginAwareGroup (installed plugin names, which commonly identify organizations or projects) folds to the fixed literal extension_command. _CLI_SKIP stays a separate product gate. - Regressions: a real Click dynamic-dispatch test stages an installed plugin named acme-private-project (lockfile + trust store + manifest, mirroring the plugin-dispatch suite's staging) and invokes the actual ouroboros_app through CliRunner -- the captured event reads extension_command with the plugin name nowhere in it; a canonical built-in still captures verbatim; and a sync guard asserts every statically registered command is in the audited set so a future built-in cannot silently degrade. Funnel mappings unchanged. With this, every caller-influenced identifier channel -- MCP tool names, durable job types, error classes, and CLI commands -- is a closed audited vocabulary. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013YX7oZyy92gYdoGKavaNQw
|
@ouroboros-agent The dynamic-CLI-command blocker from round req_1786328585_1387 is addressed in 50ff06d, completing the closed identifier vocabulary across every entry surface: CLI commands audited (src/ouroboros/telemetry.py). Actual Click dynamic-dispatch regression. A new test stages a genuine installed plugin named With this round, every caller-influenced identifier channel — MCP tool names ( Verification: telemetry + new CLI-telemetry + existing plugin-dispatch suites 106 passed under |
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: REQUEST_CHANGES
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | 50ff06d99cbf1ae1c1ed0643f4ad49b1b23ad125 |
| Request ID | req_1786330235_1392 |
| Review record | e7be8e27-cb5f-4fc2-b556-ef48a9d3c350 |
What Improved
- Adds a bounded asynchronous telemetry transport with durable anonymous identity and exact per-event property allowlists.
- Separates asynchronous submission receipts from deduplicated durable
workflow_outcomeevents and reservesverified=truefor explicitly approved evaluations. - Enforces fail-closed malformed configuration, protects telemetry controls from project
.env, and aligns installer notice and opt-out ordering. - Normalizes dynamic CLI commands, MCP tools, job types, and error classes into audited non-identifying vocabularies.
Issue Requirements
| Requirement | Status |
|---|---|
| Anonymous opt-out PostHog usage telemetry across supported runtime entrypoints | Partially met — central instrumentation exists, but project-controlled CI classification can alter measured eligibility. |
| Instrument MCP, direct CLI, and installer entry surfaces without counting internal automation as user activity | Met |
| Sample high-frequency polling tools at 1/50 with a reweighting property | Met |
| Provide three effective opt-out paths and fail closed for invalid persisted configuration | Met |
Protect telemetry controls and destinations from project-controlled .env input |
Met |
| Publish an exact event/property and weekly-active counting contract | Partially met — the documented rule exists, but untrusted project input can force the ci exclusion. |
| Distinguish submission acceptance from durable terminal and verified outcomes | Met |
| Ensure telemetry never raises, terminates, or changes command behavior | Not met — hostile BaseException values escape the new telemetry boundary. |
| Persist a random non-fingerprinted UUID and display a one-time notice before collection | Met |
| Provide critical-path regressions for privacy, adapters, persistence, installer behavior, and outcome semantics | Partially met — broad coverage passes, but the two reproduced boundary failures lack tests. |
Prior Findings Status
The prior dynamic-plugin CLI identifier concern is withdrawn: current code folds noncanonical commands to extension_command, and the real static command roster matches the audited set. Earlier opt-out, destination, malformed-config, installer-ordering, durable-outcome, tool-name, job-type, and ordinary exception-taxonomy concerns are also resolved by current evidence. The prior total failure-isolation concern remains in modified form because the remediation handles hostile Exception values but not hostile BaseException values. The project-controlled CI classification issue is newly identified.
Blockers
| # | File:Line | Severity | Finding |
|---|---|---|---|
| 1 | src/ouroboros/mcp/telemetry_boundary.py:106 | BLOCKING | The advertised total failure isolation still catches only Exception. Both _safe_error_type() and _is_logical_error() allow KeyboardInterrupt, SystemExit, or another BaseException raised by an extension-controlled metaclass/property to escape. A focused current-snapshot probe showed _safe_error_type() propagating a hostile KeyboardInterrupt, and observe_adapter_tool_call() replacing a completed Result.ok with another hostile KeyboardInterrupt from is_error. Telemetry can therefore still change or terminate command behavior through the public extension boundary. Catch BaseException inside these sanitization-only helpers and add typed-adapter regressions for hostile BaseException subclasses. |
Follow-up Findings
src/ouroboros/telemetry.py:834[warning] Theciexclusion used by the fixed weekly-active counting rule trustsCIandGITHUB_ACTIONSafter the configuration loader has imported the project-controlled.env. Neither key is denied for untrusted project input. A current-snapshot subprocess probe with only.env: CI=1produced a normal localcommand_runcarryingci=true; the same behavior excludes genuine localworkflow_outcomeevents from the published active-user rule. This lets cloned repositories silently alter telemetry semantics. Treat CI classification as operator/runtime-owned—for example, deny these keys from project.envwhile preserving pre-existing process values—and add an integration regression.
| # | File:Line | Priority | Confidence | Suggestion |
|---|-----------|----------|------------|------------|
None.
Non-blocking Suggestions
None.
Test Coverage Notes
- Ran the focused telemetry, configuration, CLI, MCP adapter, job manager, detached worker, evaluation, and installer suites with
SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0and themcp-testdependency group:748 passed, 8 skipped. - Independently derived the real Typer command and MCP-error rosters: all 27 static CLI commands and all current Ouroboros MCP exception classes match their audited telemetry sets.
- Added runtime probes outside the PR-authored tests that reproduced both blockers: escaping hostile
BaseExceptionvalues and project.envforcingci=true.
Design Notes
The centralized boundary, closed metadata vocabularies, durable outcome ownership, and fail-closed privacy resolver are directionally sound. The remaining issues are trust-boundary completeness failures rather than structural objections to the telemetry architecture.
Design / Roadmap Gate
This PR crosses persistent identity, trusted and untrusted environment resolution, installer disclosure, public CLI/MCP extension points, and durable terminal-state measurement. Replay deduplication, opt-out precedence, canonical identifier transport, and outcome ownership now fit the intended design. Merge remains blocked because sanitization is not total for the same BaseException domain the observer handles, and the fixed active-user eligibility rule still consumes a project-controlled environment signal.
Directional Notes
Review focus followed the advisory maintainer posture that operator privacy and measurement controls must dominate project input, while telemetry must remain unable to affect runtime behavior. Prior review history guided inspection only; both blockers were independently reproduced from the current source snapshot.
Test Coverage
- Ran the focused telemetry, configuration, CLI, MCP adapter, job manager, detached worker, evaluation, and installer suites with
SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0and themcp-testdependency group:748 passed, 8 skipped. - Independently derived the real Typer command and MCP-error rosters: all 27 static CLI commands and all current Ouroboros MCP exception classes match their audited telemetry sets.
- Added runtime probes outside the PR-authored tests that reproduced both blockers: escaping hostile
BaseExceptionvalues and project.envforcingci=true.
Merge Recommendation
Do not merge until telemetry sanitizers cannot propagate hostile BaseException values and CI eligibility is derived only from trusted process/runtime state rather than project .env. Add focused regressions for both reproduced paths; the broader targeted suites otherwise pass.
Review-Metadata:
verdict: REQUEST_CHANGES
head_sha: 50ff06d
request_id: req_1786330235_1392
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
…lassification Sixteenth review round on 50ff06d: - telemetry_boundary.py: _safe_error_type and _is_logical_error catch BaseException, closing the escape where an extension-controlled metaclass/property raises KeyboardInterrupt or SystemExit through the sanitization helpers -- swallowing those here is correct because the raise comes from a hostile dunder read, not a real interrupt. The observation wrappers already caught-and-reraised BaseException; record_direct_evaluation_outcome keeps except Exception since it touches no caller-controlled objects. - config/untrusted_env.py: CI and GITHUB_ACTIONS join the untrusted project denylist. The published counting rule excludes ci=true, so a cloned repository shipping CI=1 in its .env could silently deregister genuine local users from the weekly-active metric; real CI runners set these in the process environment, which the loader never overrides, so genuine CI detection is unchanged. Regressions: hostile KeyboardInterrupt/SystemExit from __name__ and is_error properties never escape at unit or adapter level and the real Result survives; project-.env CI=1 never reaches os.environ (including a real import-order subprocess whose captured event carries no ci property); genuine process-env CI still stamps ci=true. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013YX7oZyy92gYdoGKavaNQw
|
@ouroboros-agent Both findings from round req_1786330235_1392 are addressed in f3cf009: 1. Total BaseException isolation (src/ouroboros/mcp/telemetry_boundary.py) — fixed. 2. CI classification is operator/runtime-owned (src/ouroboros/config/untrusted_env.py) — fixed. Verification: telemetry + loader-env + adapter + evaluate-telemetry + CLI-telemetry suites 519 passed under |
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: APPROVE
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | f3cf009ee5d15a3ce125e5c67e971c09c42a4ade |
| Request ID | req_1786332563_1397 |
| Review record | fcc7731f-a2fd-48da-af97-bc73c5f03a52 |
What Improved
- Adds bounded, asynchronous, failure-isolated telemetry with explicit event/property allowlists and durable anonymous identity handling.
- Separates asynchronous submission receipts from terminal workflow outcomes, counting only explicitly approved evaluations as verified.
- Protects telemetry controls, destinations, and CI classification from project-controlled
.envvalues. - Normalizes extension-controlled CLI commands, MCP tools, job types, and exception classes to fixed non-identifying categories.
- Adds broad regression coverage across configuration, installer, CLI, typed/SDK MCP adapters, detached workers, durable jobs, and evaluation outcomes.
Issue Requirements
| Requirement | Status |
|---|---|
| Add anonymous, opt-out PostHog telemetry for installation, funnel conversion, entrypoint ratios, and backend reliability | Met |
| Instrument MCP calls through the shared adapter boundary, plus direct CLI and installer entrypoints | Met |
| Sample high-frequency polling tools at 1/50 and include a reweighting property | Met |
| Publish a telemetry trust contract covering event scope, uses, active-user counting, anonymity, aggregation, and changes | Met |
Support DO_NOT_TRACK, OUROBOROS_TELEMETRY=0, and persisted telemetry.enabled: false, with any disable winning |
Met |
| Prevent project-controlled environment files from overriding telemetry controls, destinations, or CI classification | Met |
| Show a one-time disclosure before collection | Partially met — structurally enforced when python3 is available; the explicitly documented text-only fallback can suppress it from nested JSON on uv-first systems without python3 |
| Count verified terminal evaluation outcomes rather than queued submissions | Met |
| Keep telemetry non-blocking, bounded, offline-safe, and failure-isolated | Met |
| Preserve stable random identity without machine fingerprinting or ephemeral IDs | Partially met — fully enforced in Python and parser-backed installer paths; the acknowledged no-python3 installer fallback is text-structural rather than JSON-structural |
Prior Findings Status
Prior blocking concerns are withdrawn on current-source evidence. Operator opt-outs and destinations are protected from project .env; malformed configuration fails closed; installer notice precedes capture; submissions and terminal outcomes are distinct; job outcomes are deduplicated; logical payload errors affect success classification; extension-controlled identifiers are normalized; hostile telemetry sanitization catches BaseException; and CI classification is operator/runtime-owned. The contributor’s explicit explanation of the no-python3 installer fallback is retained as a non-blocking follow-up rather than re-raised as a blocker.
Blockers
No in-scope blocking findings remained after policy filtering.
Follow-up Findings
| # | File:Line | Priority | Confidence | Suggestion |
|---|---|---|---|---|
| 1 | scripts/install.sh:380 | Medium | High | Consider failing telemetry closed when python3 is unavailable instead of using the text-only identity and notice fallbacks. On an otherwise supported uv-first installation, valid JSON containing only nested distinct_id/notice_shown fields is accepted by the regex paths: a focused probe returned the nested UUID and the fallback notice check suppressed disclosure. This limitation was explicitly acknowledged by the contributor as a best-effort compatibility fallback, so it is not re-raised as a blocker, but deferring collection until a structural JSON parser is available would make the installer fully match the Python trust contract. |
Non-blocking Suggestions
| 1 | scripts/install.sh:537 | Documentation | The source documents the no-python3 structural-validation gap, but TELEMETRY.md presents identity and first-run disclosure without this qualification. Either eliminate the fallback gap or disclose it in the public contract. |
Test Coverage Notes
- Reviewed telemetry, CLI, untrusted-environment, installer, adapter, job-manager, detached-worker, direct-evaluation, and start-evaluation tests.
567 passed, 8 skippedfor the focused non-SDK suites withSETUPTOOLS_SCM_PRETEND_VERSION=0.0.0and unhandled thread warnings promoted to errors.198 passedfortests/unit/mcp/server/test_adapter.pyusinguv run --extra mcp.- The initial default-environment adapter run lacked the optional
mcppackage; rerunning with the declared extra resolved all ten environment-related failures. - Independently reproduced the documented no-
python3installer fallback behavior described in the follow-up.
Design Notes
The implementation now centralizes policy in a small telemetry module and a shared MCP boundary while keeping handlers thin. Exact property allowlists, closed identifier vocabularies, fail-closed controls, and durable terminal-event ownership provide a coherent trust and measurement model.
Design / Roadmap Gate
The affected boundary spans persistent identity, installer disclosure, trusted/untrusted configuration, CLI and MCP entrypoints, SDK conversion, extension registration, durable job terminals, replay deduplication, and evaluation ownership. Current code preserves opt-out precedence, sanitizes caller-controlled metadata, distinguishes submission from completion, flushes detached terminal outcomes, and avoids duplicate direct/job-backed evaluation events. The remaining no-parser installer fallback is explicitly documented and previously explained; it is a compatibility hardening opportunity rather than a newly unresolved merge blocker.
Directional Notes
Review focus followed the advisory trust-first and replay-safe maintainer posture: privacy controls must dominate project input, telemetry must not alter command behavior, identifiers must remain non-identifying across extension boundaries, and success metrics must derive from terminal verification rather than acceptance. All merge conclusions are grounded in the current snapshot and focused execution, not memory artifacts.
Test Coverage
- Reviewed telemetry, CLI, untrusted-environment, installer, adapter, job-manager, detached-worker, direct-evaluation, and start-evaluation tests.
567 passed, 8 skippedfor the focused non-SDK suites withSETUPTOOLS_SCM_PRETEND_VERSION=0.0.0and unhandled thread warnings promoted to errors.198 passedfortests/unit/mcp/server/test_adapter.pyusinguv run --extra mcp.- The initial default-environment adapter run lacked the optional
mcppackage; rerunning with the declared extra resolved all ten environment-related failures. - Independently reproduced the documented no-
python3installer fallback behavior described in the follow-up.
Merge Recommendation
Merge is supported. Current-source inspection and 765 focused passing tests provide positive evidence that the previously blocking privacy, runtime, extension, and durable-outcome contracts are addressed. Track the no-python3 installer fallback as follow-up hardening.
Review-Metadata:
verdict: APPROVE
head_sha: f3cf009
request_id: req_1786332563_1397
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
The telemetry wiring had grown src/ouroboros/mcp/server/adapter.py to 2617 lines against its 2612-line ratchet budget, failing enforce-module-size and the in-suite test_real_repository_is_green on every Python version (the only failing test in 20090). Shrunk the PR's own additions rather than touching grandfathered code: - backend-context stamping moved into telemetry_boundary (stamp_backend_context) where the rest of the telemetry vocabulary lives; the composition root now passes the four resolved values. - call_tool's observer lambda is inlined (drops the assignment + noqa). - the _capture_telemetry escape hatch is gone: call_sdk_tool invokes adapter._call_tool_impl directly, which suppresses the typed-path observer identically (the SDK path owns its one request-outcome event), so observe_adapter_tool_call loses its always-true enabled parameter and both if-gates. adapter.py: 2611 lines, module-size OK. No behavior change: 309 telemetry/adapter/evaluate tests plus 392 job/detached/config/cli tests green, ruff/format/mypy clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013YX7oZyy92gYdoGKavaNQw
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: APPROVE
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | 3caae4aed365e9409ffe4461de8970a90ba4eacf |
| Request ID | req_1786334417_1410-retry-1-retry-2 |
| Review record | 3d6e40da-f80e-4cb9-8f57-8346e4e0e175 |
What Improved
- Adds bounded, asynchronous, failure-isolated anonymous telemetry with explicit event/property allowlists.
- Establishes operator-owned opt-out precedence across process environment, trusted user environment, persisted configuration, CLI, MCP, and installer surfaces.
- Separates asynchronous submission receipts from durable terminal outcomes and only marks completed, explicitly approved evaluations as verified.
- Canonicalizes extension-controlled CLI commands, MCP tools, job types, and exception classes to prevent identifying metadata disclosure.
- Adds replay-deduplicated job outcomes, detached-worker flushing, atomic identity repair, and one-time disclosure handling.
Issue Requirements
| Requirement | Status |
|---|---|
| Add anonymous, opt-out PostHog telemetry for install, workflow funnel, entry-surface ratio, and backend reliability measurement | Met |
| Cover supported MCP host entrypoints through a shared request boundary while excluding internal automation from CLI-versus-agent counts | Met |
| Sample polling tools at 1/50 and include a reweighting property | Met |
| Provide a documented privacy contract with an exact event/property whitelist, fixed active-user rule, aggregate-use disclosure, k-anonymity floor, and changelog policy | Met |
Support DO_NOT_TRACK, OUROBOROS_TELEMETRY=0, and persisted telemetry.enabled: false opt-outs |
Met |
| Keep telemetry non-blocking and failure-isolated using stdlib transport and a bounded queue | Met |
| Use a random persistent UUID without machine fingerprinting or PII | Met |
| Distinguish background submission acceptance from verified terminal success | Met |
| Preserve durable terminal outcomes across detached-worker exit and replay without duplicate counting | Met |
| Display and persist first-run disclosure before installer collection | Met |
Prior Findings Status
Prior blocking concerns are withdrawn on current-source evidence. The snapshot independently preserves operator-owned privacy controls, fail-closed malformed configuration handling, notice-before-capture ordering, canonical extension metadata, total observer isolation, truthful submission/terminal semantics, durable outcome deduplication, and trusted CI classification. The prior approval classification is maintained; the documented no-parser installer fallback remains a non-blocking hardening opportunity.
Blockers
No in-scope blocking findings remained after policy filtering.
Follow-up Findings
| # | File:Line | Priority | Confidence | Suggestion |
|---|---|---|---|---|
| 1 | scripts/install.sh:325 | Low | High | Replace the documented no-python3 raw-text identity/notice fallback with a structured parser or fail collection closed when parsing is unavailable. Raw grep/sed cannot distinguish top-level fields from nested or duplicate JSON keys, although normal installer environments and all Python-backed paths enforce the intended schema. |
Non-blocking Suggestions
None.
Test Coverage Notes
- Reviewed telemetry, CLI, trusted/untrusted configuration, installer, MCP adapter, detached-worker, job-manager, and direct/job-backed evaluation tests.
- Broad targeted run produced 790 passed and 23 skipped; its ten failures were caused by running adapter tests without the optional MCP SDK dependency.
- Rerunning the affected adapter, detached-worker, and evaluation telemetry suites with
--extra mcpproduced 218 passed, including all ten previously dependency-blocked tests. ruff checkpassed for the changed source and representative tests.bash -n scripts/install.shpassed;shellcheckwas unavailable in the review environment.
Design Notes
The implementation centralizes Python telemetry policy and serialization while keeping MCP instrumentation at thin request and durable-state boundaries. Installer duplication is substantial but explicitly aligned with the same opt-out, identity, disclosure, and fail-closed contracts.
Design / Roadmap Gate
The affected boundary spans persistent identity, installer disclosure, trusted and untrusted environment resolution, CLI and MCP entrypoints, SDK conversion, extension registration, durable job terminals, replay deduplication, and direct evaluation ownership. Current code preserves compatibility and opt-out precedence, sanitizes caller-controlled metadata, distinguishes submission from completion, flushes detached terminal outcomes, and prevents duplicate direct/job-backed evaluation events. No current blocking contract, persistence, replay, or runtime-boundary failure was found.
Directional Notes
Review focus followed the advisory trust-first and replay-safe maintainer posture: privacy controls must dominate project input, telemetry must never alter command behavior, extension metadata must remain non-identifying, and success metrics must derive from verified terminal evidence. All merge conclusions are independently grounded in the current snapshot and focused execution.
Test Coverage
- Reviewed telemetry, CLI, trusted/untrusted configuration, installer, MCP adapter, detached-worker, job-manager, and direct/job-backed evaluation tests.
- Broad targeted run produced 790 passed and 23 skipped; its ten failures were caused by running adapter tests without the optional MCP SDK dependency.
- Rerunning the affected adapter, detached-worker, and evaluation telemetry suites with
--extra mcpproduced 218 passed, including all ten previously dependency-blocked tests. ruff checkpassed for the changed source and representative tests.bash -n scripts/install.shpassed;shellcheckwas unavailable in the review environment.
Merge Recommendation
Merge is supported. Current-source inspection, focused runtime verification, and static checks provide positive evidence that the telemetry privacy, command-stability, extension, and durable-outcome contracts are satisfied. Track the no-python3 installer fallback as follow-up hardening.
Review-Metadata:
verdict: APPROVE
head_sha: 3caae4a
request_id: req_1786334417_1410-retry-1-retry-2
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
# Conflicts: # src/ouroboros/mcp/server/adapter.py
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: REQUEST_CHANGES
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | c2e1036369141836c6c6cfd4d10e046ff8832adc |
| Request ID | req_1786336261_1417 |
| Review record | ca704649-e819-488d-8950-1037d5b816cc |
What Improved
- Adds a documented, opt-out telemetry contract with exact event/property declarations, anonymous durable identity, and one-time disclosure.
- Separates asynchronous submission receipts from durable terminal outcomes, including replay deduplication and verified-evaluation semantics.
- Protects telemetry controls, destinations, and CI classification from project-controlled
.envinput. - Canonicalizes extension-controlled CLI, MCP tool, job, and error identifiers to non-identifying fixed values.
Issue Requirements
| Requirement | Status |
|---|---|
| Provide anonymous, opt-out PostHog telemetry across supported entry surfaces and runtimes | Partially met — instrumentation exists, but installer serialization can emit undeclared properties |
| Measure install and interview → seed → run → evolve/evaluate conversion without counting submissions as verified success | Met |
| Instrument MCP, direct CLI, installer, and durable background-job boundaries | Met |
| Sample polling tools at 1/50 with a re-weighting property | Met |
| Ship the telemetry whitelist, public counting rule, aggregate-use policy, k-anonymity floor, and changelog | Partially met — documented accurately, but the installer does not enforce the exact whitelist structurally |
Provide one-time first-run disclosure and DO_NOT_TRACK, OUROBOROS_TELEMETRY=0, and persisted-config opt-outs |
Met |
| Keep telemetry asynchronous, bounded, failure-isolated, and dependency-light | Met |
| Use a random durable UUID without PII, fingerprinting, paths, prompts, code, or arbitrary project identifiers | Partially met — identity handling is sound, but unescaped installer values can introduce arbitrary data |
| Exclude host-spawned MCP serves from direct-terminal CLI counts and internal automation from front-door ratios | Met |
Prior Findings Status
Prior privacy, opt-out, identifier-canonicalization, durable-outcome, replay, and failure-isolation concerns are resolved in the current snapshot and were not re-raised. Prior rounds had reached approval; this review introduces one newly reproduced installer serialization blocker not present in the supplied prior discussion.
Blockers
| # | File:Line | Severity | Finding |
|---|---|---|---|
| 1 | scripts/install.sh:611 | BLOCKING | _telemetry_ping constructs JSON through unescaped string concatenation, so values can alter the declared property structure or make the payload invalid. For example, placing an executable named uname earlier on PATH that returns Linux\",\"leaked\":\"project-secret causes the real payload to contain the undeclared property "leaked":"project-secret". The same issue applies to every value appended at line 615. This violates TELEMETRY.md’s exact-property and “never collect arbitrary identifying data” contract at the installer boundary. Serialize values with a real JSON encoder when available and a strict shell JSON-escaping/canonicalization fallback, constrain os/arch to a bounded vocabulary or safe token format, and add an installer regression using quote/control-character-bearing command output. |
Follow-up Findings
| # | File:Line | Priority | Confidence | Suggestion |
|---|---|---|---|---|
| None. |
Non-blocking Suggestions
None.
Test Coverage Notes
- Reviewed the telemetry, installer, CLI, configuration, MCP adapter, detached-worker, job-manager, and evaluation telemetry tests.
- Focused run without the optional MCP extra: 828 passed, 23 skipped; 10 adapter transport failures were solely due to the missing
mcppackage. - Required-extra rerun: 339 passed, 5 skipped with
--extra mcpandPytestUnhandledThreadExceptionWarningpromoted to an error. - Ruff check and format verification passed for all changed Python files;
bash -n scripts/install.shpassed. ShellCheck was unavailable. - Added a focused runtime probe independently demonstrating undeclared installer-property injection through unescaped
unameoutput; no existing regression covers this path.
Design Notes
The shared Python telemetry boundary is well isolated and enforces closed event, property, and identifier vocabularies. The installer independently reimplements serialization but lacks equivalent structural enforcement, creating a cross-runtime trust-contract mismatch.
Design / Roadmap Gate
Persistence, replay deduplication, terminal outcome ownership, malformed-config fail-closed behavior, detached-worker flushing, extension identifier folding, and CLI/MCP compatibility are supported by current source and focused tests. The remaining affected boundary is installer transport serialization: unlike the Python serializer, it permits property-shape mutation through unescaped command-derived values, directly violating the PR’s public exact-property and privacy contracts.
Directional Notes
Review focus followed the advisory trust-first posture: operator opt-outs must dominate project input, success must reflect terminal verification, and every telemetry surface must enforce the published privacy vocabulary. Prior review history and maintainer memory guided inspection only; the blocker is grounded in the current installer source and a focused runtime reproduction.
Test Coverage
- Reviewed the telemetry, installer, CLI, configuration, MCP adapter, detached-worker, job-manager, and evaluation telemetry tests.
- Focused run without the optional MCP extra: 828 passed, 23 skipped; 10 adapter transport failures were solely due to the missing
mcppackage. - Required-extra rerun: 339 passed, 5 skipped with
--extra mcpandPytestUnhandledThreadExceptionWarningpromoted to an error. - Ruff check and format verification passed for all changed Python files;
bash -n scripts/install.shpassed. ShellCheck was unavailable. - Added a focused runtime probe independently demonstrating undeclared installer-property injection through unescaped
unameoutput; no existing regression covers this path.
Merge Recommendation
Do not merge until installer telemetry uses structurally safe JSON serialization and a regression proves hostile quote/control-character-bearing values cannot add properties, disclose arbitrary data, or corrupt the payload. The remaining telemetry architecture and focused suites otherwise provide strong positive evidence.
Review-Metadata:
verdict: REQUEST_CHANGES
head_sha: c2e1036
request_id: req_1786336261_1417
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
Eighteenth review round on c2e1036: - install.sh: _telemetry_ping no longer builds JSON by unescaped string concatenation. os/arch are token-constrained at the source (fullmatch [A-Za-z0-9._-]{1,32} or the literal unknown), defusing a hostile uname on PATH regardless of encoder availability. With python3 the entire payload is built by json.dumps with every value passed via argv -- never interpolated into the -c source -- so hostile values can only ever be string contents of their own declared property, and keys are defensively whitelisted to [A-Za-z0-9_]+. Without python3 the fallback pushes every value through a strict safe-token filter (tr -cd, 64-char cap, unknown for empty) before concatenation, which loses nothing legitimate while making structure mutation impossible. - Regressions drive the real _telemetry_ping (extracted-function driver): the reviewer's exact hostile uname emitting 'Linux","leaked":"project-secret' yields a payload that parses as JSON with no leaked key and os=unknown on BOTH the python3 and no-python3 paths, and a normal ping asserts the exact declared property structure (json.loads + exact key set). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013YX7oZyy92gYdoGKavaNQw
|
@ouroboros-agent The installer serialization blocker from round req_1786336261_1417 is addressed in 7666d94: Structural encoding (scripts/install.sh Regressions drive the real CI note: all 14 checks are green on the merge-resolved head (the previous module-size failure was fixed in 3caae4a by moving the PR's additions out of the grandfathered adapter module). |
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: REQUEST_CHANGES
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | 7666d9404fd092f90b3a397bf9c6883ad1dd7ec4 |
| Request ID | req_1786337804_1429 |
| Review record | 6b45f1eb-9954-4fa2-b88d-55c7087f08cf |
What Improved
- Adds bounded, asynchronous telemetry with strict event/property allowlists and stable random UUID identities.
- Separates asynchronous submission receipts from verified durable workflow outcomes, including replay deduplication.
- Protects telemetry controls, destinations, and CI classification from project-controlled
.envinput. - Sanitizes extension-controlled command, tool, job, and error identifiers across CLI and MCP boundaries.
- Fixes installer JSON serialization so hostile values cannot mutate the payload structure.
Issue Requirements
| Requirement | Status |
|---|---|
| Anonymous opt-out PostHog telemetry for installation, workflow funnels, entrypoint ratios, and runtime success rates | Partially met — instrumentation exists, but the installer can ignore a valid duplicate-key persisted opt-out |
| Shared MCP/CLI/install instrumentation with polling sampled 1/50 and reweighting metadata | Met |
| Published event whitelist, aggregate-use policy, fixed active-user rule, k-anonymity floor, and changelog | Met |
| One-time first-run notice and three authoritative opt-out paths | Partially met — ordinary paths work, but trusted .env duplicate-key semantics diverge between installer and application |
| Stdlib-only bounded, asynchronous, failure-isolated transport | Met |
| Stable random UUID identity without machine fingerprinting or PII | Met |
| Distinguish submission acceptance from terminal and verified outcomes | Met |
| Avoid internal automation and MCP serve boots inflating terminal CLI usage | Met |
| Disable telemetry during tests and provide focused telemetry regressions | Partially met — broad coverage exists, but duplicate trusted-control precedence is missing |
Prior Findings Status
The prior installer structural-serialization blocker is withdrawn: current source uses JSON encoding on the Python path, constrained fallback serialization without Python, and focused hostile-value coverage. Earlier privacy, identifier-sanitization, durable-outcome, replay, and adapter-isolation concerns are also addressed in the current snapshot. Approval cannot be maintained because current verification found a new trusted .env precedence mismatch that can bypass an installer opt-out.
Blockers
| # | File:Line | Severity | Finding |
|---|---|---|---|
| 1 | scripts/install.sh:172 | BLOCKING | _telemetry_load_user_env makes duplicate keys in the trusted ~/.ouroboros/.env file first-wins because it exports the first value and then skips every later occurrence once the variable is set. The application resolver delegates to dotenv_values, where duplicate keys are last-wins (src/ouroboros/config/loader.py:207). I reproduced OUROBOROS_TELEMETRY=1 followed by OUROBOROS_TELEMETRY=0: the installer reports telemetry enabled with value 1, while the application resolves value 0 and disables telemetry. Consequently, a valid persisted opt-out can be ignored by install.sh, which then displays the notice and emits install telemetry contrary to the published same-controls contract. Preserve real process-environment precedence, but resolve all assignments within the trusted file using the application’s last-wins semantics; add an installer regression covering an enabling entry followed by a disabling duplicate for both OUROBOROS_TELEMETRY and DO_NOT_TRACK. |
Follow-up Findings
| # | File:Line | Priority | Confidence | Suggestion |
|---|---|---|---|---|
| None. |
Non-blocking Suggestions
None.
Test Coverage Notes
- Reviewed the telemetry, installer, configuration, CLI, MCP adapter, durable-job, detached-worker, and evaluation telemetry tests.
- Initial focused run completed with 778 passed and 23 skipped; 10 adapter failures were caused solely by running without the optional MCP dependency.
- Rerunning the relevant adapter/job/evaluation suites with
--extra mcpproduced 389 passed. - Evaluation/Ralph and run/evaluate chaining suites produced 53 passed.
bash -n scripts/install.sh, Ruff on the changed Python files, and mypy on 12 changed source files passed.- Existing installer tests cover ordinary trusted
.envopt-outs and quoting, but do not cover duplicate telemetry-control assignments; the reproduced first-wins/last-wins divergence remains untested.
Design Notes
The telemetry boundary is now largely well-factored: serialization and privacy vocabulary are centralized, MCP observation is thin, and durable terminal ownership is explicit. The remaining defect comes from maintaining a second hand-written .env resolver whose precedence semantics differ from the application SSOT.
Design / Roadmap Gate
Persistence, identity repair, exact-property serialization, project-environment denial, extension identifier folding, adapter failure isolation, durable outcome ownership, replay deduplication, and detached-worker flushing are supported by current source and focused tests. The remaining affected boundary is compatibility between the installer and application resolvers for the same trusted persistent control file. Because the installer may collect when the application resolves that file as opted out, the advertised cross-runtime privacy contract is not yet executable consistently.
Directional Notes
Review focus followed the trust-first maintainer posture: operator opt-outs must dominate collection across every runtime, telemetry must not affect command behavior, and success metrics must represent terminal verification. Prior reviews and memory guided inspection only; the blocker is independently supported by current source and a focused runtime reproduction.
Test Coverage
- Reviewed the telemetry, installer, configuration, CLI, MCP adapter, durable-job, detached-worker, and evaluation telemetry tests.
- Initial focused run completed with 778 passed and 23 skipped; 10 adapter failures were caused solely by running without the optional MCP dependency.
- Rerunning the relevant adapter/job/evaluation suites with
--extra mcpproduced 389 passed. - Evaluation/Ralph and run/evaluate chaining suites produced 53 passed.
bash -n scripts/install.sh, Ruff on the changed Python files, and mypy on 12 changed source files passed.- Existing installer tests cover ordinary trusted
.envopt-outs and quoting, but do not cover duplicate telemetry-control assignments; the reproduced first-wins/last-wins divergence remains untested.
Merge Recommendation
Do not merge until install.sh matches the application’s duplicate-key semantics while retaining real process-environment precedence, with focused regressions proving that a later persisted opt-out disables installer notice and collection. The rest of the telemetry architecture has strong positive verification.
Review-Metadata:
verdict: REQUEST_CHANGES
head_sha: 7666d94
request_id: req_1786337804_1429
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
…tenv Nineteenth review round on 7666d94: - install.sh: _telemetry_load_user_env no longer exports mid-loop. The per-line 'skip if already set' guard existed to preserve real process-env precedence, but after the loop exported the first file occurrence the same guard blocked every later occurrence too -- silently making duplicates within the trusted file first-wins while the application's dotenv_values resolves them last-wins, so OUROBOROS_TELEMETRY=1 followed by =0 disabled the app but not the installer. Now: process-env presence is snapshotted before the file is read, occurrences accumulate into per-key holding variables (last-wins for free), and the post-loop export applies the file value only for keys the real environment had not already set. - Regressions: enable-then-disable duplicates for both OUROBOROS_TELEMETRY and DO_NOT_TRACK end disabled with no notice or events; disable-then-enable ends enabled (last-wins is not sticky-disable); a real process-env opt-out still beats a duplicated file enable. Installer suite 79 passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013YX7oZyy92gYdoGKavaNQw
|
@ouroboros-agent The duplicate-key precedence blocker from round req_1786337804_1429 is addressed in aab2884: Last-wins within the trusted file, process env still first (scripts/install.sh Regressions: enable-then-disable duplicates for BOTH Verification: installer suite 79 passed, |
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: REQUEST_CHANGES
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | aab288446cf8d00ced22dca79755eaccd44f0157 |
| Request ID | req_1786338908_1431 |
| Review record | 7f3d7152-081d-422e-b76d-faf9dfe8647c |
What Improved
- Adds bounded, failure-isolated telemetry with strict event/property allowlists, durable anonymous identity, sanitized extension boundaries, sampled polling, and separate submission versus terminal-outcome semantics.
- The latest revision fixes the previously reported duplicate-key precedence issue while preserving real process-environment precedence.
Issue Requirements
| Requirement | Status |
|---|---|
| Add anonymous telemetry across installer, CLI, MCP, and durable execution boundaries | Met |
| Measure install/funnel, CLI-versus-agent entry, and per-backend outcomes | Met |
| Distinguish asynchronous submission receipts from durable or direct terminal outcomes | Met |
| Count verified activity only from completed evaluations with explicit approval | Met |
| Enforce an exact event/property privacy whitelist and sanitize extension-controlled identifiers | Met |
Honor DO_NOT_TRACK, OUROBOROS_TELEMETRY, and persisted configuration consistently across every collection surface |
Not met |
| Ensure malformed or unreadable configuration fails telemetry closed | Met |
| Provide one-time disclosure before installer collection | Met for covered syntax; partially met overall because ignored persisted opt-outs still trigger disclosure and collection |
| Use bounded, asynchronous, failure-isolated transport without changing command results | Met |
| Persist a random, non-fingerprinted anonymous UUID and remove it during normal data-directory uninstall | Met |
| Sample polling tools at 1/50 with a reweighting property | Met |
Document collection, counting, public aggregate use, and opt-out behavior in TELEMETRY.md |
Met as documentation; executable opt-out parity remains incomplete |
Prior Findings Status
The prior duplicate-key blocker is withdrawn: current code implements last-wins semantics within the trusted file and retains real process-environment precedence, with focused passing regressions. The broader installer/application resolver-parity concern remains modified rather than repeated: current evidence identifies additional valid dotenv syntax that still makes the installer collect while the application opts out.
Blockers
| # | File:Line | Severity | Finding |
|---|---|---|---|
| 1 | scripts/install.sh:148 | BLOCKING | The installer still does not interpret the trusted ~/.ouroboros/.env with the same grammar as the application, so valid persisted opt-outs can be ignored. The application uses dotenv_values() and therefore decodes OUROBOROS_TELEMETRY="0\\n" to "0\n", which get_telemetry_enabled() strips and treats as disabled. The shell parser copies the quoted contents literally as 0\\n, which does not match its disabling values. A full installer probe on the current snapshot displayed the notice and emitted both install events for this file while the application resolved telemetry as disabled. Quoted dotenv keys such as 'OUROBOROS_TELEMETRY'=0 produce the same disagreement. This violates the documented “any one opt-out wins” and cross-runtime trusted-control contract. Make the installer resolver cover the application’s accepted dotenv grammar—or fail closed when it cannot—and add full-installer regressions for escaped quoted values and quoted keys. |
Follow-up Findings
None.
Non-blocking Suggestions
None.
Test Coverage Notes
373 passed, 8 skipped: telemetry, installer, and configuration suites.484 passed: adapter, job manager, detached worker, and evaluation telemetry suites with themcpextra.56 passed: CLI telemetry and evaluation chaining suites.bash -n scripts/install.sh, focused Ruff checks, and focused mypy checks passed.- Existing installer tests cover ordinary quoted/commented values and duplicate precedence, but not the valid dotenv forms reproduced in the blocker.
Design Notes
The telemetry boundary is generally well-factored: transport and schema enforcement are centralized, MCP observation is isolated from handlers, and terminal outcomes derive from durable state. The remaining hand-written installer dotenv parser duplicates a library-owned grammar and is still the weak point in the trust contract.
Design / Roadmap Gate
Persistence, identity repair, exact payload serialization, project-environment denial, extension identifier folding, adapter failure isolation, durable outcome ownership, replay deduplication, detached-worker flushing, and duplicate-key precedence are supported by current source and focused tests. The remaining affected boundary is compatibility between the application and installer resolvers for the same trusted persistent control file. Because the installer can collect when the application resolves that file as opted out, the advertised cross-runtime privacy contract is not yet executable consistently.
Directional Notes
Review focus followed the trust-first maintainer posture: operator-owned privacy controls must dominate every runtime, while success metrics must come from verified terminal evidence. Prior review history and maintainer memory guided inspection only; the blocker is independently demonstrated by current source and full-installer runtime probes.
Test Coverage
373 passed, 8 skipped: telemetry, installer, and configuration suites.484 passed: adapter, job manager, detached worker, and evaluation telemetry suites with themcpextra.56 passed: CLI telemetry and evaluation chaining suites.bash -n scripts/install.sh, focused Ruff checks, and focused mypy checks passed.- Existing installer tests cover ordinary quoted/commented values and duplicate precedence, but not the valid dotenv forms reproduced in the blocker.
Merge Recommendation
Do not merge until the installer handles all relevant dotenv forms accepted by the application—or conservatively disables telemetry when parity cannot be established—and regressions prove escaped quoted opt-outs and quoted keys suppress notice and collection. The rest of the telemetry architecture has strong focused verification.
Review-Metadata:
verdict: REQUEST_CHANGES
head_sha: aab2884
request_id: req_1786338908_1431
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
…ed .env Twentieth review round on aab2884: - install.sh: keys wrapped in one layer of matching quotes ('OUROBOROS_TELEMETRY'=0, "DO_NOT_TRACK"=1) now strip to the bare form before the allowlist check -- real dotenv parity where parity is cheap. Escape-bearing double-quoted values ("0\n") are the opposite case: dotenv decodes the escapes, the shell copies them literally, and no hand-rolled parser can faithfully chase that grammar -- so an allowlisted key carrying one sets an ambiguity flag that _telemetry_enabled treats as an opt-out for the entire run. An opt-out the installer cannot resolve is honored, never ignored; the deliberate asymmetry (an ambiguous enable also disables) diverges from the application only in the safe, under-collecting direction. - Regressions: escape-bearing disable and enable values both produce no notice and no events; single- and double-quoted keys disable via real parsing; a plain quoted value without backslashes still enables (fail-closed triggers on ambiguity only). Installer suite 84 passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013YX7oZyy92gYdoGKavaNQw
|
@ouroboros-agent The dotenv-grammar parity blocker from round req_1786338908_1431 is addressed in 720a7c9, taking the fail-closed branch you sanctioned for grammar the shell cannot faithfully interpret: Quoted keys — real parity. A key wrapped in one layer of matching quotes ( Escape-bearing double-quoted values — fail closed. Full-installer regressions: your exact probe |
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: REQUEST_CHANGES
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | 720a7c91c8ef4c9cd6637ecbd62a3a0e2b482494 |
| Request ID | req_1786340056_1435 |
| Review record | 88465760-1415-4356-996e-3f59c7e871e4 |
What Improved
- Adds failure-isolated, allowlisted telemetry with durable job-outcome semantics, sanitized extension identifiers, replay deduplication, stable anonymous identity, and broad focused test coverage.
- Prior fixes now protect telemetry controls from project
.env, fail closed on malformed configuration, distinguish submissions from verified outcomes, and serialize installer payloads safely.
Issue Requirements
| Requirement | Status |
|---|---|
| Provide anonymous, opt-out telemetry for install and workflow funnels across supported runtimes | Partially met — instrumentation exists broadly, but installer opt-out enforcement still diverges from the application for valid trusted dotenv input. |
| Measure terminal CLI versus in-agent entry and per-backend outcomes without internal automation pollution | Met |
| Use a single MCP boundary plus CLI and installer trigger sites | Met |
Enforce DO_NOT_TRACK, OUROBOROS_TELEMETRY=0, and persisted telemetry.enabled: false consistently |
Not met — the installer emits for a valid multiline persisted environment opt-out that disables application telemetry. |
| Count active users only from non-CI verified evaluation outcomes | Met |
| Keep transport asynchronous, bounded, failure-isolated, and dependency-light | Met |
| Use a random persisted UUID without machine fingerprinting or identifying payload fields | Met |
| Display and persist a one-time notice before first collection | Met when telemetry is correctly resolved as enabled; the resolver bug can incorrectly activate both notice and collection. |
| Publish an exact event/property whitelist and trusted-control contract | Partially met — serialization and property controls are strong, but the published cross-runtime opt-out contract is not fully executable. |
Prior Findings Status
Prior concerns around duplicate precedence, quoted keys, escape-bearing values, safe serialization, durable outcomes, and trusted-source authority are addressed in the current snapshot. The prior cross-runtime dotenv-parity concern is modified rather than withdrawn: the reviewed escape cases now fail closed, but current source still fails the same contract for valid physically multiline quoted bindings.
Blockers
| # | File:Line | Severity | Finding |
|---|---|---|---|
| 1 | scripts/install.sh:164 | BLOCKING | The installer still disagrees with the application on valid multiline dotenv values, allowing collection despite a persisted opt-out. python-dotenv accepts a physically multiline quoted binding such as OUROBOROS_TELEMETRY="0 followed by " on the next line and resolves it to "0\n"; get_telemetry_enabled() strips that to 0 and disables telemetry. The installer reads one line at a time, sees no closing quote at line 176, skips the binding without setting _TELEMETRY_USER_ENV_AMBIGUOUS, and leaves telemetry enabled. An end-to-end installer probe with this exact trusted file displayed the notice and emitted install_started, while the application returned enabled=False. This violates the documented “any one opt-out wins” cross-runtime privacy contract. Use the same dotenv parser where available or fail closed whenever an allowlisted quoted binding cannot be conclusively parsed, including multiline values, and add a full-installer regression covering multiline OUROBOROS_TELEMETRY and DO_NOT_TRACK opt-outs. |
Follow-up Findings
| # | File:Line | Priority | Confidence | Suggestion |
|---|---|---|---|---|
| --- | --- | --- | --- | --- |
| None. | N/A | N/A | N/A | None. |
Non-blocking Suggestions
| None. | N/A | N/A | None. |
Test Coverage Notes
- Reviewed telemetry, installer, configuration, adapter, direct-evaluation, detached-worker, and durable-job tests.
tests/unit/test_telemetry.py, CLI telemetry, and config loader: 300 passed, 5 skipped.- Installer suite: 81 passed, 3 skipped.
- Evaluation telemetry, detached worker, and job manager: 156 passed.
- Targeted adapter selection: 2 passed, 10 skipped, 221 deselected.
- Added a focused application-versus-installer runtime probe for a physically multiline quoted opt-out; it reproduced the blocking mismatch and actual installer event emission.
Design Notes
The telemetry architecture is generally well separated: serialization and privacy vocabulary are centralized, MCP adapters remain thin, submissions are distinct from durable outcomes, and terminal replay uses deterministic deduplication. The remaining blocker is the duplicated dotenv grammar in the shell installer.
Design / Roadmap Gate
Identity persistence, event allowlists, extension folding, adapter failure isolation, durable terminal ownership, replay deduplication, detached-worker flushing, configuration failure handling, and installer JSON safety have positive current-source and focused-test evidence. Merge remains blocked at the installer/application compatibility boundary because the two runtimes assign different meanings to the same trusted persistent control file, causing over-collection rather than a safe undercount.
Directional Notes
Review focus followed the trust-first maintainer posture: operator-owned opt-outs must dominate every collection surface, while success metrics must represent verified terminal evidence. Prior review history and maintainer memory guided inspection only; the blocker is independently demonstrated by current source and runtime reproduction.
Test Coverage
- Reviewed telemetry, installer, configuration, adapter, direct-evaluation, detached-worker, and durable-job tests.
tests/unit/test_telemetry.py, CLI telemetry, and config loader: 300 passed, 5 skipped.- Installer suite: 81 passed, 3 skipped.
- Evaluation telemetry, detached worker, and job manager: 156 passed.
- Targeted adapter selection: 2 passed, 10 skipped, 221 deselected.
- Added a focused application-versus-installer runtime probe for a physically multiline quoted opt-out; it reproduced the blocking mismatch and actual installer event emission.
Merge Recommendation
Do not merge until install.sh conservatively handles multiline dotenv bindings accepted by the application—or fails telemetry closed whenever such grammar cannot be resolved—and full-installer regressions prove multiline persisted opt-outs suppress both notice and collection.
Review-Metadata:
verdict: REQUEST_CHANGES
head_sha: 720a7c9
request_id: req_1786340056_1435
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
…iguity Twenty-first review round on 720a7c9: - install.sh: a quoted value with no closing quote on the same physical line is, to dotenv, the start of a valid MULTILINE value the line-by-line shell reader cannot follow -- so for an allowlisted key both unclosed-quote branches now set _TELEMETRY_USER_ENV_AMBIGUOUS (unconditional opt-out for the run) instead of silently skipping the binding, closing the case where a persisted multiline opt-out disabled the application but not the installer. Trailing garbage after a legitimate closing quote stays a plain skip: dotenv itself rejects that line, so both sides already agree -- the asymmetry is documented. - Regressions: physically multiline OUROBOROS_TELEMETRY and DO_NOT_TRACK opt-outs emit no notice and no events; a multiline enabling-looking value also stays silent (safe-direction asymmetry); the round-7 unclosed-quote test flips to the new fail-closed contract. Installer suite 87 passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013YX7oZyy92gYdoGKavaNQw
|
@ouroboros-agent The multiline-binding blocker from round req_1786340056_1435 is addressed in ed7444b: Unclosed quotes are multiline ambiguity, not silent skips (scripts/install.sh). A quoted value with no closing quote on the same physical line is — to Full-installer regressions: your exact probe — |
There was a problem hiding this comment.
Review — ouroboros-agent[bot]
Verdict: APPROVE
Metadata
| Field | Value |
|---|---|
| PR | #1908 |
| HEAD checked | ed7444b6071bee2eeb6c909ef04ae41a4bc7f85c |
| Request ID | req_1786341160_1439 |
| Review record | 7bf99648-f19d-4b90-baa9-cc707e6beedd |
What Improved
- Adds bounded, asynchronous, failure-isolated anonymous telemetry with strict event/property allowlists and durable UUID identity.
- Separates asynchronous submission receipts from durable terminal outcomes, requiring explicit evaluation approval for verified success.
- Enforces operator-owned opt-outs and destinations against project-controlled
.env, malformed configuration, and installer parsing ambiguity. - Instruments CLI, MCP, installer, direct evaluation, background jobs, and detached-worker exit paths while sampling polling tools.
- The latest revision fixes the prior multiline trusted-
.envmismatch by failing installer telemetry closed when quoted bindings cannot be parsed faithfully.
Issue Requirements
| Requirement | Status |
|---|---|
| Provide anonymous, opt-out PostHog telemetry for install, workflow funnel, CLI-versus-agent usage, and backend outcomes | Met |
| Instrument the shared MCP chokepoint, direct CLI callback, and installer while sampling polling tools at 1/50 with a reweighting property | Met |
| Publish a telemetry trust contract covering the exact event/property whitelist, aggregate uses, fixed active-user rule, k-anonymity floor, and change policy | Met |
| Support DO_NOT_TRACK, OUROBOROS_TELEMETRY, and persisted telemetry.enabled opt-outs with operator-owned precedence | Met |
Prevent project-controlled .env values from changing telemetry controls, destination, key, or CI classification |
Met |
| Fail telemetry closed for invalid or unreadable persisted configuration and ambiguous installer control input | Met |
| Use stdlib-only, bounded, asynchronous, non-raising transport that drops events when delivery is unavailable | Met |
| Persist a random UUID identity without machine fingerprinting and remove it through normal uninstall data cleanup | Met |
| Distinguish asynchronous acceptance from verified terminal outcomes and count only explicitly approved completed evaluations | Met |
| Capture MCP serve attachment separately and avoid inflating direct-CLI counts with internal automation and plumbing | Met |
| Show and persist a one-time first-run notice before installer collection | Met |
Prior Findings Status
The prior multiline trusted-.env compatibility concern is withdrawn. Current scripts/install.sh marks unclosed allowlisted quoted values as ambiguous and _telemetry_enabled fails closed, with full-installer regressions covering multiline telemetry and DO_NOT_TRACK bindings. Earlier concerns around operator authority, malformed configuration, exact payload structure, durable terminal ownership, replay deduplication, adapter failure accounting, and detached-worker delivery also have current-source and focused-test evidence of remediation.
Blockers
No in-scope blocking findings remained after policy filtering.
Follow-up Findings
| # | File:Line | Priority | Confidence | Suggestion |
|---|---|---|---|---|
| None. |
Non-blocking Suggestions
| 1 | scripts/install.sh:111 | Documentation | The comment claims double-quoted keys are handled “exactly like dotenv_values(),” but python-dotenv retains the double quotes as part of a key such as "DO_NOT_TRACK", while the installer strips them and treats the binding as an opt-out. This only under-collects and is therefore safe, but the parity claim and corresponding test description should be corrected or explicitly documented as a conservative installer extension. |
Test Coverage Notes
- Reviewed telemetry, configuration, CLI, MCP adapter, evaluation, job-manager, detached-worker, and installer coverage.
SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0 /root/.local/bin/uv run --extra mcp python -m pytest -q tests/unit/mcp/server/test_adapter.py tests/unit/mcp/tools/test_evaluate_telemetry.py tests/unit/mcp/test_job_manager.py tests/unit/mcp/test_detached_worker.py— 389 passed.SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0 /root/.local/bin/uv run python -m pytest -q tests/unit/scripts/test_install_runtime_selection.py— 84 passed, 3 skipped.- Broader telemetry/configuration test selection produced 661 passes and 20 skips; the remaining adapter transport cases were subsequently verified successfully with the required MCP extra.
bash -n scripts/install.shpassed, and Ruff passed for the reviewed Python source and test files.
Design Notes
The design keeps telemetry behind narrow serialization, request-observation, and durable-job boundaries rather than coupling analytics to orchestration internals. Privacy controls fail closed, event vocabularies are bounded, and terminal success derives from authoritative evaluation/job evidence.
Design / Roadmap Gate
The affected boundary spans trusted configuration, persistent identity, installer behavior, CLI and MCP entrypoints, adapter failures, durable job state, replay deduplication, and detached process exit. Current code preserves opt-out authority, safely under-collects when installer parsing is ambiguous, separates submission from outcome semantics, deduplicates durable outcomes, and flushes the active-user event before detached-worker exit. Compatibility and failure-isolation paths have positive focused-test evidence.
Directional Notes
Review focus followed the trust-first maintainer posture: operator-owned privacy controls must dominate project input, declared telemetry schemas must match executable payloads, and verified success must come from terminal evidence rather than dispatch receipts. Prior reviews and memory guided inspection only; the final assessment is based on the current snapshot and focused execution.
Test Coverage
- Reviewed telemetry, configuration, CLI, MCP adapter, evaluation, job-manager, detached-worker, and installer coverage.
SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0 /root/.local/bin/uv run --extra mcp python -m pytest -q tests/unit/mcp/server/test_adapter.py tests/unit/mcp/tools/test_evaluate_telemetry.py tests/unit/mcp/test_job_manager.py tests/unit/mcp/test_detached_worker.py— 389 passed.SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0 /root/.local/bin/uv run python -m pytest -q tests/unit/scripts/test_install_runtime_selection.py— 84 passed, 3 skipped.- Broader telemetry/configuration test selection produced 661 passes and 20 skips; the remaining adapter transport cases were subsequently verified successfully with the required MCP extra.
bash -n scripts/install.shpassed, and Ruff passed for the reviewed Python source and test files.
Merge Recommendation
Merge is recommended. No current blocking runtime, privacy, persistence, API-contract, or critical coverage defect was found. The remaining double-quoted-key parity wording is a safe-direction documentation cleanup and does not need to block.
Review-Metadata:
verdict: APPROVE
head_sha: ed7444b
request_id: req_1786341160_1439
review_profile: memory-aware-zero-trust-v2
advisory_memory_only: true
Reviewed by ouroboros-agent[bot] via Codex deep analysis
## Why `ouroboros mcp serve` accepted no credentials on its network transports. An instance bound to a routable address let anyone who could reach the port call `ouroboros_execute_seed` — caller-supplied YAML run through a local agent runtime with that runtime's full file and shell authority, in a caller-supplied directory. Reproducible with: ```bash ouroboros mcp serve --transport streamable-http --host 0.0.0.0 --port 8080 ``` The default (`stdio` on `localhost`) and every loopback bind were never exposed — the SDK enables DNS-rebinding protection for `127.0.0.1` / `localhost` / `::1` on its own. Plugin and Claude Desktop installs are unaffected. ## Root cause Not "auth defaulted to `AuthMethod.NONE`". Authentication was **not implemented** for network transports: - `credentials` never reached `call_tool` — nothing extracted them from HTTP headers. - `serve()` raised `ValueError` if any auth method was configured, so turning auth on made the server refuse to start. - No `TransportSecuritySettings` were passed, and the SDK only synthesizes them for three literal host spellings. Every other bind, including `0.0.0.0`, ran with `Host`/`Origin` validation off. ## What changed - `serve()` refuses a non-loopback bind without credentials, naming the capability at risk rather than failing abstractly. - Bearer-token auth is wired through the SDK's `TokenVerifier`/`AuthSettings` to Ouroboros's existing `Authenticator`, so one credential authority covers both the HTTP edge and the per-tool `SecurityLayer`. The SDK's decision crosses back as an `AuthContext`, restoring the client identity authorization and rate limiting key on — **rate limiting is no longer blanket-refused**. - Explicit `TransportSecuritySettings` for every bind the SDK does not auto-protect. - `execute_seed`'s `cwd` can be confined to operator-chosen roots (`--workspace-root`). Checked *before* the existence test so a refusal cannot be used to probe paths. - CLI: `--auth-token` (env `OUROBOROS_MCP_AUTH_TOKEN`), `--allow-remote`, `--allowed-host`, `--allowed-origin`, `--workspace-root`, and a startup banner stating the actual posture. - `docs/cli-reference.md` no longer demonstrates a bare `--host 0.0.0.0`. ## Breaking change A remote bind now needs `--auth-token`, `--allow-remote`, and `--allowed-host` for wildcard binds. An existing `--host 0.0.0.0` command refuses to start until those are supplied. **`stdio` and loopback binds are unchanged** — no credential, no new flags. ## Verification End to end against a real `0.0.0.0` bind (not mocks), re-run after rebasing onto current `main`: | request | result | |---|---| | anonymous | `401` | | wrong token | `401` | | correct token | `200` + full `initialize` handshake | | forged `Host: attacker.example.com` | `421` | Tests: 61 new in `tests/unit/mcp/server/test_network_security.py`; `tests/unit/mcp/server` + `tests/unit/cli` green (2287 passed); `ruff` and `mypy` clean. ## Note for reviewers The rebase onto `main` interacts with #1908 — telemetry split `call_tool` into an observer wrapper plus `_call_tool_impl`, and moved the SDK dispatch body into `telemetry_boundary.call_sdk_tool`. The auth-context bridge had to follow into both. Git's auto-merge produced a version where `call_tool` accepted `auth_context` and silently dropped it while `_call_tool_impl` referenced an undefined name; that is resolved here, and the e2e run above is the proof the live path still carries the identity. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01MzysvKLDuJW9bkKQFBnP5B --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Closes #1909
Summary
MCPServerAdapter.call_tool(covers Claude/Codex stdio, legacy serve wrapper, and the codexooointercept), plus CLI callback andinstall.shpings; polling tools sampled 1/50 with asample_ratere-weighting propertyTELEMETRY.md(event whitelist, declared uses incl. public aggregate stats, fixed counting rule "1 active user = 1 anonymous ID with ≥1 successful run/week — installs/CI/retries don't count", k-anonymity floor, append-only changelog), one-time first-run notice, 3 opt-out paths (DO_NOT_TRACK,OUROBOROS_TELEMETRY=0,config telemetry.enabled)Design notes
~/.ouroboros/telemetry.json(no PII, no fingerprinting; removed byouroboros uninstall); the embeddedphc_key is PostHog's public write-only project key, safe by design in OSSouroboros mcp serveboots are captured asmcp_serve_started(session-attach denominator) and excluded from terminal-CLI counts so host-spawned serves don't inflate direct usageooo auto) and detached job workers bypasscall_tool, so internal automation cannot pollute the cli-vs-agent ratiotests/conftest.pyforce-disables telemetry suite-wide; telemetry unit tests neutralize the embedded key and inject a fake transportChecks passed
Test plan
Credit
@code-yeongyu suggested this Posthog to track user data in Ouroboros funnel.
🤖 Generated with Claude Code