Skip to content

Analytics: deploy evidence, record endpoints and bounded queries - #263

Merged
vmelikyan merged 1 commit into
mainfrom
feat/analytics-evidence
Oct 14, 2026
Merged

vmelikyan merged 1 commit into
mainfrom
feat/analytics-evidence

Conversation

@vmelikyan

@vmelikyan vmelikyan commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Analytics counted build rows and inferred outcomes from status columns that any run could overwrite. Nothing showed which records a number counted, and long windows cost the database seconds per request.

What changes

  • The deploy pipeline records its own evidence. Migration 038 adds build_events, the first-ready, first-rollout, last-teardown and namespace stamps on builds, the analytics_retention setting, three small build_events indexes and a deploys("buildId") index unless one exists. The worker records every request, claim, block, exit and finish with its outcome, services, per-service results and failure reason. A request resolves by its own run id.
  • New endpoints summarize deploy requests and MCP tool calls and list the records behind every number. deployments/requests and mcp/calls reuse the summary queries cut by a slice, and a live-database test proves every slice total matches its summary. Environment analytics report evidence levels and link every record that still has a page. Lifetimes tell recorded end times from estimates and measure runtime. A daily job applies the retention setting.
  • Database cost: JIT is off for analytics statements, at most four analytics transactions run at once with a short queue, record lists scan only their slice, and agent queries decompress each run plan once.

Rollout notes

  • Migration 038 runs at worker start. On a large database its concurrent index builds can exceed the worker liveness budget of about three minutes. Run pnpm db:migrate once from a one-off pod before deploying, or raise the probe for this release. The migration resumes after an interruption: finished indexes are kept, an invalid one is rebuilt, and the builds backfills run in id batches of 5,000. A killed run leaves the knex lock set; clear it with knex migrate:unlock.
  • Every connection now sets timezone=UTC and datestyle=ISO,MDY through the options startup parameter. Check SHOW timezone on the target. If it is not UTC, rows written before this release keep the old offset. PgBouncer older than 1.20 needs ignore_startup_parameters = options.
  • analytics_retention keeps MCP tool calls and build events forever by default. Set mcpToolCallDays and buildEventDays in global_config to prune.

Validation

10,000 tests with coverage at 98.12/91.86/98.12/98.52, the gated live-database suite, the server tsconfig, and the migration exercised fresh and resumed on a copy of a populated database. pnpm ts-check carries pre-existing errors in unrelated files; this branch adds none.

Pairs with https://github.com/GoodRxOSS/lifecycle-ui/pull/93.

…number

Analytics counted build rows and inferred outcomes from status columns that any run could
overwrite. Nothing showed which records a number counted, and long windows cost the database
seconds per request. The deploy pipeline now records its own evidence, every number opens its
records, and the queries are bounded.

Migration 038 adds the build_events table and the first-ready, first-rollout, last-teardown and
namespace stamps on builds. It adds the analytics_retention setting, three small build_events
indexes and a deploys("buildId") index unless one exists. It resumes after an interrupted run:
finished indexes are kept, an invalid one is rebuilt, and the builds backfills run in id batches.
The reconciliation worker records every deploy request with its origin, every run claim, every
block and every exit that stops a run. Each finish records its outcome, services, per-service
results and failure reason. A request resolves by its own run id. The last finish that followed a
rollout decides. A takeover counts as superseded. A service that fails before it has a row fails
the run. A teardown that stopped a run, or preceded it, counts as torn down.

New endpoints summarize deploy requests and MCP tool calls and list the records behind each
number. deployments/requests and mcp/calls reuse the summary queries, cut by a slice. A slice is
an outcome, a source, a failure reason, a tool, a user, a client application, one chart bucket or
the previous period. A live-database test proves every slice total matches its summary count.
environments/records accepts the evidence levels and a chart bucket. environments/pull-requests
lists the PR records behind PRs recorded and PRs deployed. Agent runs and sessions accept a chart
bucket and the in_progress status group. Environment analytics report evidence levels (recorded,
deploy requested, rolled out, live, ready), exclude the seed record and link every record that
still has a page. Lifetimes tell recorded end times from estimates and measure runtime from the
first deploy. MCP audits every tool call with its client application, and a daily job applies
the retention setting. Telemetry stats use the shared calendar window, and agent cost estimates
price cached tokens.

Every analytics transaction runs with JIT off, at most four at once with a short queue, and
record lists scan only their slice. Agent queries decompress each run plan once.

Gated live-database and in-memory worker suites cover the attribution rules, and the OpenAPI
schemas describe every field the UI reads.
@vmelikyan
vmelikyan requested a review from a team as a code owner October 14, 2026 07:31
@vmelikyan
vmelikyan merged commit fe3f6c2 into main Oct 14, 2026
5 checks passed
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