Skip to content

Add source access to AI investigations#233

Merged
Makisuo merged 4 commits into
mainfrom
agent/github-investigation-source-access
Jul 20, 2026
Merged

Add source access to AI investigations#233
Makisuo merged 4 commits into
mainfrom
agent/github-investigation-source-access

Conversation

@Makisuo

@Makisuo Makisuo commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

What changed

  • add read-only MCP tools to list connected repositories, search source, and read files at a branch, tag, or commit
  • route access through an org-scoped, provider-neutral Effect service backed by active VCS installations
  • teach investigation prompts to use explicit incident windows, representative traces, and repository/revision telemetry
  • treat repository content as untrusted input and source findings as hypotheses until runtime evidence confirms them
  • document the GitHub Contents permission used by investigations

Why

AI investigations could inspect telemetry but could not inspect a user's connected GitHub repository. That made root-cause analysis stop at symptoms and encouraged guesses about code or deployments. The investigation prompt also allowed vague time ranges and over-reliance on individual traces.

Safety and impact

Repository access is read-only, organization-scoped, limited to repositories persisted for an active installation, and bounded by result, line, and character limits. Search qualifiers cannot be used to escape the selected repository.

Users with GitHub connected can now correlate incidents with the exact deployed source revision when telemetry provides repository and commit attributes.

Validation

  • API VCS source tests: 3 passed
  • chat investigation tests: 22 passed
  • chat-flue TypeScript check: passed
  • staged diff whitespace check: passed

The full API typecheck is currently blocked by unrelated query-engine errors already present in the worktree; none of the new source-access files appeared in those diagnostics.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

@github-actions

Copy link
Copy Markdown

Ingest Rust Test + Benchmark Results

Commit: 281763951c020a66c41cbf3ea661f4cc80808e82

Load Benchmark — tinybird mode, median of 3 run(s) vs main

Metric main (median) PR (median) Delta
Requests/sec 11826.20 12190.28 +3.1% better
Rows/sec 118261.95 121902.81 +3.1% better
p50 latency 5.16 ms 5.13 ms -0.6% better
p95 latency 9.97 ms 10.08 ms +1.1% worse
p99 latency 12.04 ms 10.66 ms -11.4% better
Export catch-up 0.026 s 0.026 s +0.9% worse
Max RSS 16.32 MiB 17.69 MiB +8.4% worse
Failures 0 0 same

Same code path on both sides (same LOAD_TEST_INGEST_MODE), so the delta column is meaningful. Numbers come from ubuntu-latest, which is noisy — treat single-digit-percent deltas as noise.

PR load benchmark JSON (per-iteration)
[
  {
    "ingest_mode": "tinybird",
    "requests": 2000,
    "successes": 2000,
    "failures": 0,
    "rows_sent": 20000,
    "rows_exported": 20000,
    "imports": 11,
    "duration_seconds": 0.163437469,
    "export_catchup_seconds": 0.026063778,
    "request_rps": 12237.096011319167,
    "row_rps": 122370.96011319167,
    "p50_ms": 5.118,
    "p95_ms": 9.992,
    "p99_ms": 10.659,
    "max_rss_mb": 18.9765625,
    "max_cpu_percent": 0.0,
    "avg_cpu_percent": 0.0
  },
  {
    "ingest_mode": "tinybird",
    "requests": 2000,
    "successes": 2000,
    "failures": 0,
    "rows_sent": 20000,
    "rows_exported": 20000,
    "imports": 12,
    "duration_seconds": 0.164065123,
    "export_catchup_seconds": 0.026430306,
    "request_rps": 12190.281294580811,
    "row_rps": 121902.81294580811,
    "p50_ms": 5.133,
    "p95_ms": 10.076,
    "p99_ms": 10.592,
    "max_rss_mb": 16.1171875,
    "max_cpu_percent": 0.0,
    "avg_cpu_percent": 0.0
  },
  {
    "ingest_mode": "tinybird",
    "requests": 2000,
    "successes": 2000,
    "failures": 0,
    "rows_sent": 20000,
    "rows_exported": 20000,
    "imports": 11,
    "duration_seconds": 0.176060647,
    "export_catchup_seconds": 0.025781821,
    "request_rps": 11359.721971259143,
    "row_rps": 113597.21971259142,
    "p50_ms": 5.378,
    "p95_ms": 10.525,
    "p99_ms": 12.007,
    "max_rss_mb": 17.6875,
    "max_cpu_percent": 0.0,
    "avg_cpu_percent": 0.0
  }
]
main load benchmark JSON (per-iteration)
[
  {
    "ingest_mode": "tinybird",
    "requests": 2000,
    "successes": 2000,
    "failures": 0,
    "rows_sent": 20000,
    "rows_exported": 20000,
    "imports": 10,
    "duration_seconds": 0.169116095,
    "export_catchup_seconds": 0.025593303,
    "request_rps": 11826.195490145394,
    "row_rps": 118261.95490145394,
    "p50_ms": 5.18,
    "p95_ms": 9.966,
    "p99_ms": 12.037,
    "max_rss_mb": 15.98828125,
    "max_cpu_percent": 0.0,
    "avg_cpu_percent": 0.0
  },
  {
    "ingest_mode": "tinybird",
    "requests": 2000,
    "successes": 2000,
    "failures": 0,
    "rows_sent": 20000,
    "rows_exported": 20000,
    "imports": 11,
    "duration_seconds": 0.170300876,
    "export_catchup_seconds": 0.026793444,
    "request_rps": 11743.920800501344,
    "row_rps": 117439.20800501344,
    "p50_ms": 5.162,
    "p95_ms": 10.546,
    "p99_ms": 14.521,
    "max_rss_mb": 16.32421875,
    "max_cpu_percent": 0.0,
    "avg_cpu_percent": 0.0
  },
  {
    "ingest_mode": "tinybird",
    "requests": 2000,
    "successes": 2000,
    "failures": 0,
    "rows_sent": 20000,
    "rows_exported": 20000,
    "imports": 10,
    "duration_seconds": 0.145852568,
    "export_catchup_seconds": 0.025837656,
    "request_rps": 13712.477109076339,
    "row_rps": 137124.7710907634,
    "p50_ms": 4.501,
    "p95_ms": 5.291,
    "p99_ms": 9.079,
    "max_rss_mb": 17.0546875,
    "max_cpu_percent": 0.0,
    "avg_cpu_percent": 0.0
  }
]

WAL-acked microbench (cargo bench --bench ingest_bench)

   Compiling maple-ingest v0.1.0 (/home/runner/_work/maple/maple/apps/ingest)
    Finished `bench` profile [optimized] target(s) in 12.99s
     Running benches/ingest_bench.rs (target/release/deps/ingest_bench-581d2100de893627)
Gnuplot not found, using plotters backend
test ingest_accept/logs_10_rows_wal_ack ... bench:       89127 ns/iter (+/- 6216)

thread 'main' (5075) panicked at benches/ingest_bench.rs:73:22:
accept traces: QueueUnavailable("Telemetry WAL lane is full")
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
test ingest_accept/traces_10_spans_wal_ack ... 
error: bench failed, to rerun pass `--bench ingest_bench`

cargo test

test telemetry::tests::metric_encoder_matches_all_tinybird_datasource_shapes ... ok
test telemetry::tests::metrics_emit_exactly_the_jsonpaths_declared_in_datasources_ts ... ok
test telemetry::tests::migrate_legacy_shard_relocates_frames_into_lanes ... ok
test telemetry::tests::pipeline_can_start_for_clickhouse_only_without_tinybird_credentials ... ok
test telemetry::tests::clickhouse_export_drops_passworded_non_https_endpoint_without_sending ... ok
test telemetry::tests::sampling_keeps_errors_even_when_ratio_low ... ok
test telemetry::tests::scraper_contract::scraper_otlp_json_decodes_with_gateway_serde_and_encodes_to_rows ... ok
test telemetry::tests::signal_tag_round_trips_all_variants ... ok
test telemetry::tests::pipeline_e2e_exports_metrics_to_fake_tinybird ... ok
test telemetry::tests::telemetry_signal_as_str_is_canonical_lowercase ... ok
test telemetry::tests::timestamp_has_nano_precision ... ok
test telemetry::tests::timestamps_match_clickhouse_datetime64_nine_format ... ok
test telemetry::tests::trace_encoder_matches_tinybird_row_shape ... ok
test telemetry::tests::traces_emit_exactly_the_jsonpaths_declared_in_datasources_ts ... ok
test telemetry::tests::wal_partial_drain_advances_cursor_without_truncating ... ok
test telemetry::tests::pipeline_e2e_exports_gzip_ndjson_to_fake_tinybird ... ok
test telemetry::tests::wal_round_trips_frame ... ok
test telemetry::tests::wal_truncates_after_full_drain_allowing_further_appends ... ok
test telemetry::tests::pipeline_e2e_exports_traces_to_fake_tinybird ... ok
test telemetry::tests::pipeline_exports_ready_org_to_clickhouse_without_tinybird_calls ... ok
test telemetry::tests::slow_clickhouse_lane_does_not_block_cosharded_tinybird_org ... ok
test telemetry::tests::clickhouse_breaker_sheds_after_threshold_failures ... ok

test result: ok. 36 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.74s

     Running unittests src/bin/load_test.rs (target/debug/deps/load_test-661a0aa1eb3f6d6d)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running unittests src/main.rs (target/debug/deps/maple_ingest-c33bf80c577edb95)

running 38 tests
test autumn::tests::allowed_only_no_balance_field ... ok
test autumn::tests::flat_hardcap_with_remaining_allows ... ok
test autumn::tests::flat_sub_one_gb_remaining_still_allows ... ok
test autumn::tests::flat_overage_allows ... ok
test autumn::tests::flat_hardcap_depleted_blocks ... ok
test autumn::tests::flat_unlimited_allows ... ok
test autumn::tests::nested_balance_object_depleted_blocks ... ok
test autumn::tests::nested_overage_allows ... ok
test autumn::tests::null_balance_no_subscription_blocks ... ok
test autumn::tests::nested_balance_object_with_remaining_allows ... ok
test tests::clickhouse_destination_is_terminal_in_dual_mode ... ok
test autumn::tests::unrecognized_shape_returns_none ... ok
test tests::clickhouse_destination_uses_native_pipeline_even_in_forward_mode ... ok
test tests::api_error_from_pipeline_maps_variants_to_status ... ok
test tests::api_error_kind_maps_status_to_stable_label ... ok
test tests::cloudflare_log_record_maps_body_severity_and_attributes ... ok
test tests::cloudflare_timestamps_support_rfc3339_unix_and_unix_nano ... ok
test tests::clickhouse_target_resolver_requires_current_schema ... ok
test tests::cloudflare_validation_payload_is_detected ... ok
test tests::cloudflare_ndjson_payload_parses_multiple_records ... ok
test tests::clickhouse_target_resolver_decrypts_current_schema_password ... ok
test tests::decrypt_aes256_gcm_matches_node_crypto_fixture ... ok
test tests::extract_ingest_key_returns_sentinel_literal_unchanged ... ok
test tests::enrichment_overwrites_tenant_fields ... ok
test tests::hash_is_deterministic ... ok
test tests::rejection_span_status_is_error_only_for_5xx ... ok
test tests::clickhouse_target_resolver_rejects_password_over_http ... ok
test tests::resolve_ingest_key_returns_none_when_hash_missing ... ok
test tests::resolve_ingest_key_keeps_stale_schema_on_managed_native_path ... ok
test tests::resolve_ingest_key_returns_self_managed_false_when_no_settings_row ... ok
test tests::resolve_ingest_key_returns_self_managed_true_when_active_settings_row ... ok
test tests::sentinel_token_matches_only_exact_literal ... ok
test tests::tinybird_destination_keeps_forward_mode_on_forward_path ... ok
test tests::resolve_connector_refreshes_routing_before_auth_cache_expires ... ok
test tests::resolve_ingest_key_refreshes_routing_before_auth_cache_expires ... ok
test autumn::tests::fails_open_on_transport_error ... ok
test tests::resolve_ingest_key_serves_last_known_routing_when_refresh_fails ... ok
test tests::forward_mode_switches_ready_org_to_clickhouse_without_forwarding_again ... ok

test result: ok. 38 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.19s

   Doc-tests maple_ingest

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Makisuo and others added 2 commits July 21, 2026 00:59
# Conflicts:
#	apps/api/src/routes/query-engine.http.ts
#	packages/domain/src/generated/tinybird-project-manifest.ts
#	packages/domain/src/tinybird/datasources.ts
…orker-free

The new source-code MCP tool pulls VcsSourceService → VcsProviderRegistry →
GithubProvider → VcsSyncQueue into the tool registry's import graph. VcsSyncQueue
imported WorkerEnvironment from the @maple/effect-cloudflare barrel, which
re-exports durable-object-namespace.ts and its static `import "cloudflare:workers"`.
That crashed every plain-bun consumer of the registry (e.g. the measure-tokens
Token Cost CI job: "Cannot find package 'cloudflare:workers'"), leaving head.json
unwritten and failing the check.

Switch to the `/worker-environment` subpath (dynamic, catch-guarded
cloudflare:workers import) — the same convention already used by EmailService,
AiTriageService, InvestigationService, etc.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Makisuo
Makisuo marked this pull request as ready for review July 20, 2026 23:15
@pullfrog

pullfrog Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Your Pullfrog Router balance is exhausted.

You have a card on file but auto-reload is disabled, so runs paused once your balance went past the overdraft buffer.

Top up balance → · Enable auto-reload →

Pullfrog  | ⚠️ this action is pinned to a commit SHA, which freezes the cleanup step — switch to @v0 or keep the SHA fresh with Dependabot | Rerun failed job ➔View workflow run | via Pullfrog | Using Claude Opus𝕏

@Makisuo
Makisuo merged commit ca70204 into main Jul 20, 2026
7 of 8 checks passed
@Makisuo
Makisuo deleted the agent/github-investigation-source-access branch July 20, 2026 23:15
@Makisuo
Makisuo deployed to pr-preview July 20, 2026 23:15 — with GitHub Actions Active
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant