Repository navigation
The trend tools answer in time buckets sized to the window: a day of get_file_io_trend is 34 KB, not 1.4 MB (#3897) - #3968
Merged
Conversation
#3897) get_file_io_trend, get_lock_wait_trend, get_query_duration_trend, get_procedure_duration_trend, get_pg_io_trend and get_pg_database_trend returned every collection: a default day of file I/O was 12,500 points and 1.4 MB, a week 9.8 MB. Each now buckets its collections on a shared origin, sized to a 200-point budget, with bucket_minutes to ask for another width up to a per-read cap (refused, never clamped). Counts are summed, rates and ratios recomputed from the bucket's sums, the worst single collection kept as the peak; the payload says what a point is (bucket, bucket_minutes, aggregate_note). File I/O charts (database, file type) lines ranked by stall with the tail folded into one (other) line, database_name for one database per file; lock waits chart the LCK family with a per-type legend. Lite parity in DuckDB; the web viewer reads the same tools at a chart budget. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Z4T51J4E6L8fjriPHpsif
…and (#3897) get_query_heatmap's bucket_minutes and metric refusals went through local helpers, the bucket one behind a ?? chain whose shared first operand the refusal census accepted for the whole chain. Both are now McpHelpers.Refusal at the call site on both SKUs, and the census checks every operand of a ?? chain. The payload census gains a 600-file server; the web PostgreSQL trend tables show each bucket's peak and worst interval; two docs lines describe the bucketed shape. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Z4T51J4E6L8fjriPHpsif
The CoalesceOperands helper landed between LastAssignmentOf's doc comment and its signature, stacking two summaries on one member (DocCommentHygieneTests). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Z4T51J4E6L8fjriPHpsif
…3962) The bare-sentence and hand-built-envelope rules only saw a tool's own return expressions, so a bare sentence returned through a same-file private helper passed - get_query_heatmap's refusals hid that way until #3897. The census now follows each `return Helper(...)` into the method declared in the same file and holds every result arm of its return expressions (ternaries split at depth zero, conditions excluded) to the same two rules. Floored at 50 helpers followed (60 on the tree today); a fixture proves the walk fires on the heatmap's old shape and not on a helper that builds the refusal, a miss built through McpHelpers.Status, a ?. / ?? expression, or a method in another file. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Z4T51J4E6L8fjriPHpsif
This was referenced Sep 23, 2026
erikdarlingdata
enabled auto-merge (squash)
September 23, 2026 01:53
2 of 3 tasks
erikdarlingdata
added a commit
that referenced
this pull request
Sep 23, 2026
…ection-health policy run waits out a launch that beat the park (#3982) * Chunk-exclusion tests count a bitmap plan's chunks once, and the collection-health policy run waits out a launch that beat the park Two CI flakes that blocked #3968 and #3972 on code neither PR touched. LatestValueLookbackLivePostgresTests reported "planned 4 chunks" for a 24-hour read whose plan scanned two. TimescaleDB names a chunk's indexes after the chunk, so under a bitmap plan the "Bitmap Index Scan on _hyper_12_11_chunk_..._idx" child matched the chunk pattern too, and the count doubled whenever the planner picked bitmap scans. The same pattern lived in FleetReadsAreBoundedByTheFleetTests and CaptureDownChunkOrderTests. One shared PlanChunkScans helper now ends the match on the chunk name, and PlanChunkScansTests pins it against the plan CI printed. CollectionHealthAggregateTests' run_job failed 55P03 "concurrent refresh": collection_health_hourly's policy has no initial_start, so TimescaleDB launches its first run the moment the product commits it, before the fixture can park it. RunPolicyAsync now retries 55P03 for up to 30 s. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdmA4ND1wLSqA91ax1m4xv * The chunk counters #3980 added go through PlanChunkScans too #3980 merged to dev with two more ChunkScans callers in LatestValueLookbackTests and a fourth copy of the double-counting pattern in PgTargetConfigSnapshotBoundTests. Both now use the shared helper. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdmA4ND1wLSqA91ax1m4xv --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
erikdarlingdata
added a commit
that referenced
this pull request
Sep 23, 2026
…3920, #3927, #3931, #3932, #3940, #3942, #3946, #3947, #3950, #3952, #3955, #3956, #3957, #3964, #3965, #3966, #3968, #3972, #3975, #3979, #3980, #3981, #3983, #3984, #3985) (#3989) The wave's fix PRs deliberately carried no CHANGELOG edits (parallel-agent hot-spot protocol); each agent reported its entry and this commit lands them together, byte-verified against origin/dev. Claude-Session: https://claude.ai/code/session_01GdmA4ND1wLSqA91ax1m4xv Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
erikdarlingdata
added a commit
that referenced
this pull request
Sep 23, 2026
… PostgreSQL query duration) buckets to a point budget, the same way #3968 bucketed the first five (#3960) (#4007) Reuses TrendBuckets/TrendBudget/TrendPayloads from #3968 rather than inventing a second mechanism. Gauges (memory, tempdb, CPU) publish the bucket's average with peak_* beside it; get_wait_trend and get_perfmon_trend's rate points sum work over summed seconds, never averaging per-collection rates. get_memory_trend's grant join moves from nearest-snapshot-within-30-seconds to same-bucket, averaging every grant snapshot in a memory point's bucket with the largest kept as peak_granted_mb. Extends the #3968-era test infrastructure for the new tools: TrendBucketsTests' cap sweep, TrendPayloadBudgetLiveTests' payload census (seeds and measures all six), and a new TrendFamilyBucketingLiveTests with hand-verified bucket math for each read's distinctive shape (wait's time-weighting, CPU's unclamped own-clock bucketing, tempdb's averaged-space/busiest-session split, perfmon's three-way interval-completeness shaping, the PG duration pair's recomputed mean). Fixes fallout in existing census/inventory tests from centralizing per-tool JSON building into the shared TrendPayloads builders: DarlingPgReadSqlParsesLiveTests (a shared SQL fragment reflected as a standalone query), ConsumedTimestampFrameDisciplineTests (a de-skewed site moving out of its per-SKU file), PerfmonCounterTypeRungTests and DarlingCustomViewsTests (bucket_minutes changing a payload shape a fixed-count assertion assumed), and their Lite twins. Claude-Session: https://claude.ai/code/session_01GdmA4ND1wLSqA91ax1m4xv Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This was referenced Sep 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3897. Closes #3962.
Why
The trend tools returned every collection in the window, so an answer's size was window × cadence × series. Measured on DARLING01:
get_file_io_trendat its 24 h default (SQL2022) was 12,500 points and 1.4 MB, and a week was 9.8 MB.get_lock_wait_trendwas 349 KB (2 MB over a week), and 96% of its rows (3,368 of 3,523) were zeros.get_pg_io_trend/get_pg_database_trendwere 448 KB / 294 KB over a day.The store was never the bottleneck.
EXPLAIN ANALYZEof every read on DARLING01 came in at 270 ms or less at 168 h. The one exception isget_pg_io_trend's automatic subject choice (3.8 s at 168 h, filed as #3961).Where the diagnosis needed correcting (measured)
get_file_io_trendalready capped itself at the top 10 files, so the "600 files → about 30 MB" extrapolation does not hold. What scaled it was the window: 9.8 MB at 168 h on any server. It also published indistinguishable rows. tempdb's nine data files shared one database name per timestamp, which accounts for 11,250 of 12,500 rows, and the web chart's pivot kept one of each.get_lock_wait_trenddoes scale with the number of LCK types: one row per type per collection.query_statsandprocedure_statshave a rollup tier, and the duration pair already routes to it. None of the other three reads has anything to route to.What changes
One shared contract (
PerformanceMonitor.Common/Mcp, both SKUs):TrendBucketspicks the width from a ladder (1, 2, 5, 10, 15, 30 minutes, 1 to 24 hours).bucket_minutes(1–1440) asks for another width, up to a per-read cap sized so the largest answer stays under 256 KB.date_binand DuckDBtime_bucketshare one origin, so both SKUs bin the same rows the same way.TrendPayloadsbuilds the file I/O and lock-wait envelopes once for both SKUs.bucket,bucket_minutes,aggregate_note.peak_*/worst_*keep the single most extreme collection, so a spike survives.Per tool:
get_file_io_trend(other)line, pooled collection by collection before bucketing. All lines are charted when there are six or fewer.database_namenarrows to one database, charted per file.serieslegend gives each line's window totals.get_lock_wait_trendwait_typeslegend lists the types that waited, andwait_types_idlecounts the rest.empty.get_query_duration_trend/get_procedure_duration_trendunrated_collections.peak_elapsed_ms_per_secondis the busiest collection, or the busiest hour on the rollup.effective_startis the first collection, not a bucket boundary.get_pg_io_trend/get_pg_database_trendpoint_countnow counts buckets, and the newinterval_countis the old count.peak_*/worst_cache_hit_pct.Surfaces:
/api/readpassesbucket_minutesthrough; an unparseable value is refused. It charts at a 1,500-point budget, so a day stays per-minute on one line. The file I/O panel pivots by line, and the PostgreSQL trend tables gain peak/worst columns.LocalDataService.TrendBuckets.cs. The desktop charts' per-collection reads are untouched.get_query_heatmap. Itsbucket_minutesandmetricrefusals (both SKUs) were bare sentences with noinvalidstatus. They are nowMcpHelpers.Refusal.??operand, not just the first.return Helper(…)into the same-file helper and holds each result arm of that helper's return expressions to the bare-sentence and hand-built rules. Ternaries are split at depth zero and conditions excluded. 60 helpers are followed on the tree today, floored at 50, and a fixture proves the walk fires on the heatmap's old shape and not on its neighbours.bucket_minutesincluded.Payload changes (deliberate, since "results identical" is not possible here)
wait_type; the per-type view iswait_types.bucketis a width word.aggregate_noteis always set.bucket_minutes,unrated_collections,peak_elapsed_ms_per_second.unrated_notesentence now counts collections, not points.point_countcounts buckets, andinterval_countis new.interval_secondsis the seconds its intervals covered.No store migration.
Test plan
get_file_io_trend(SQL2022)get_lock_wait_trend(SQL2022)get_query_duration_trend(SQL2022)get_pg_io_trend(PG18)get_pg_database_trend(PG18)as_of, my build vs the deployed build:interval_countequals the oldpoint_count.TrendPayloadBudgetLiveTests, new): a week of one-minute collections plus a 600-file server.TrendBucketsTests: the width table, the budget invariant over every window (1–168 h) × line count (1–6) at both budgets, the edge bucket, the refusals naming the width that fits, and the hourly tier.TrendBucketingLiveTests(Darling, live) andTrendBucketingToolTests(Lite) plant the same rows and assert the same hand-worked figures: the fold per collection, ratios of sums, null over no I/O, the restart row, time-weighting, unrated collections, and the window-start stamp.DarlingLockWaitTrendTests/LockWaitTrendToolTests: family plus legend, one interval per collection, and the all-idle window.TryParseOptionalInt.TrendBucketsproducers are accepted as shared refusals, with executed shapes.??operand is walked.DARLING_TEST_SQL,DARLING_TEST_PGRUNTIME, the log target, or symlink rights.StatusBarSizeReadLockTests.GetUsedDataSizeMb_WhenTheWriteLockIsHeld_GivesUpInsteadOfBlockingandAnalysisPassTokenThreadingTests.TheReadLockWaitIsAbandonableWhileAWriterHoldsIt("the writer never took the lock"). Both passed 3/3 when re-run alone: the known AnalysisPass threading flake family.Folded in: #3962, the refusal census's helper blind spot.
Still open, and why:
get_pg_io_trend's default subject choice. The store's collation is alreadyC, so the cheap fix that keeps the same semantics gains nothing (5.8 s vs 6.2 s). An endpoint form measured 0.30 s with an identical ranking. It needs a decision on reset detection, and TimescaleDB'sfirst()/last()do not exist on a plain-PostgreSQL store.🤖 Generated with Claude Code
https://claude.ai/code/session_018Z4T51J4E6L8fjriPHpsif