Skip to content

get_pg_logging_audit/get_pg_io_stats/get_pg_wait_sampling move reading guidance off tools/list (#3898) - #4081

Merged
erikdarlingdata merged 1 commit into
devfrom
feature/3898-content-pg-audit-io
Sep 23, 2026
Merged

erikdarlingdata merged 1 commit into
devfrom
feature/3898-content-pg-audit-io

Conversation

@erikdarlingdata

@erikdarlingdata erikdarlingdata commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Refs #3898.

Why

A client that loads Darling's whole MCP catalog pays for every tool description before it asks a
question. get_pg_logging_audit, get_pg_io_stats and get_pg_wait_sampling served 2,032 to 2,086
characters each. This PR moves the reading guidance in those three descriptions off tools/list. It goes
into get_tool_guide, which serves it on request. Nothing was deleted.

What changes

Each tool's Description literal now carries the <<GUIDE>> marker. tools/list serves the text before
the marker (the head) plus the standard pointer sentence. get_tool_guide serves the text after the
marker (the tail). The tail is the tool's full original prose, verbatim, minus one issue reference removed
under D4. See below for that removal.

Before and after (Darling only)

None of the three tools has a Lite twin.

Tool Before (served chars) After: head (served) After: tail
get_pg_logging_audit 2,086 546 2,048
get_pg_io_stats 2,045 610 2,111
get_pg_wait_sampling 2,032 590 2,127

(Tail lengths are the raw text get_tool_guide serves, before its own JSON wrapping.)

D2 parameter cap

get_pg_io_stats's limit parameter description was 235 characters. That is over the 200-character cap
for a converted tool's parameters. I tightened the wording from This is what bounds the page, read truncated to know whether the window held more to Bounds the page, read truncated for more. The new
text is 194 characters. No fact was dropped. Nothing needed to move to the tail.

Corrections

None. I checked each description's claims against the tool body and found nothing wrong.

D4 removals

get_pg_logging_audit's original text read ...says PLANNED where that consumer does not ship yet (#3601/#3602/#3603).... The parenthetical issue list came off the wire. The sentence still says PLANNED
without naming the issues. The CHANGELOG keeps those issue numbers.

No other issue references, anecdotes, or WIRE CHANGE notices were present in these three descriptions.

Re-pointed pins

  1. DarlingMcpPgLoggingAuditToolsTests.TheToolDescription_StatesWhatItJudges_AndThatItReadsStoredConfig
    used to read the raw, unsplit Description attribute. I split its assertions by kind. Five guardrail
    facts now assert against the served head. They are the stored snapshot, never the live server, LATEST IS A TIME,
    captured_at, and what partial means. Four narrative facts assert against the tail instead. They are the full
    seven-setting roster, the RDS/Aurora remedy syntax, the get_pg_plan_capture_readiness hand-off, and
    PLANNED. Reading the raw attribute passed by accident. The head and tail are one string at the attribute
    level. Splitting it confirms which facts actually reach tools/list.
  2. PgWaitInstrumentDisclosureTests.BothToolDescriptions_NameTheThreeTiers covers both
    get_pg_wait_sampling (mine) and get_pg_wait_stats (a different, still-unconverted lane's tool). I
    re-pointed only the get_pg_wait_sampling half. extension_sampled, service_sampled and FLOOR now
    assert against the head. The "Aurora native > ... > service sampler" ordering asserts against the tail.
    I left the get_pg_wait_stats half reading the raw literal, since that tool is out of this PR's scope.

Left unmodified, verified still green by construction:

  • McpPageContractTests.EveryPercentTool_NamesItsDenominator_AndItsPageBound_InItsDescription reads the
    raw Description attribute across all five PercentTools entries. Three of them (get_pg_top_queries,
    get_pg_wait_stats, get_pg_kernel_stats) belong to a different, in-flight lane. SHARES ARE OF THE WINDOW, NOT OF THE PAGE and every required key name are present in my two tools' heads or tails. This
    test passes without changes. I left its mechanism alone. Editing it risks changing behavior for tools
    outside this PR.
  • McpLatestSnapshotStampTests already lists get_pg_logging_audit under DarlingOnlyStamped and reads
    the raw attribute. LATEST IS A TIME and captured_at are both in the head, so no change was needed.
  • Hand-kept tool-name rosters (CrossAppMcpToolInventoryPinTests, ServerPageTabsTests, and others):
    my three tools were already listed by name. Nothing was renamed, added, or removed (D8), so these needed
    no edits.

D9 traps

  1. Q: get_pg_logging_audit shows log_lock_waits as unknown. Is lock-wait logging off?
    Correct: unknown means the setting is missing from the stored snapshot. Nothing is inferred about
    its real state. This is not the same as off.
    Prevents it: the head's unknown means the setting is missing from the snapshot, not the same as off, and nothing is inferred.
  2. Q: get_pg_logging_audit rates log_min_duration_statement as partial. Should it be raised to
    instrumented?
    Correct: no. For this one setting, the threshold is the recommended posture. Setting it to 0 logs
    every statement the server runs.
    Prevents it: the head's partial means a THRESHOLD is filtering; for log_min_duration_statement that threshold IS the recommended posture, not a shortfall.
  3. Q: get_pg_logging_audit was read five minutes after a config change. Does it reflect the change?
    Correct: not necessarily. It reads the stored hourly snapshot, never the live server.
    Prevents it: the head's STORED configuration snapshot pg_server_config already collects hourly, never the live server and LATEST IS A TIME: captured_at is when that snapshot was taken.
  4. Q: get_pg_io_stats shows read_time_ms: null on every row. Is the disk instant?
    Correct: no. track_io_timing is off by default in PostgreSQL, so time fields are null when
    untracked. A false 0.000 reads as an impossibly fast disk.
    Prevents it: the head's track_io_timing is OFF by default... never a false 0.000.
  5. Q: get_pg_io_stats shows writes: null for a combination. Were there no writes?
    Correct: unmeasured, not zero. Write counters are always null on Amazon Aurora.
    Prevents it: the head's Write counters are always null on Aurora, never a true zero.
  6. Q: Three get_pg_io_stats rows show pct_of_total_reads adding up to 40%. Did the rest of the
    activity happen outside this window?
    Correct: no. The percentages divide by the whole window's total_reads. That total is computed on
    the same statement as the rows, so a truncated page never sums to 100%. The other 60% is combinations
    past the cap, in the same window.
    Prevents it: the head's SHARES ARE OF THE WINDOW, NOT OF THE PAGE: pct_of_total_reads/ pct_of_total_read_time divide by total_reads/total_read_time_ms.
  7. Q: get_pg_wait_sampling answers with instrument: service_sampled. Is that as reliable as the
    extension?
    Correct: no. service_sampled is a floor, not parity. It undercounts sub-second waits.
    Prevents it: the head's instrument says extension_sampled (10ms profile) or service_sampled (a FLOOR that undercounts sub-second waits).
  8. Q: get_pg_wait_sampling shows estimated_wait_ms: 5000 for one event. Is that a measured
    duration?
    Correct: no. It is the sample count multiplied by the instrument's period. That is an estimate, not
    a measured duration.
    Prevents it: the head's Results are SAMPLE COUNTS, not measured durations: estimated_wait_ms = samples x period.
  9. Q: get_pg_wait_sampling's busiest row has event_type: CPU. Does that mean the busiest wait is
    CPU-related?
    Correct: no. A CPU row means the backend was running, not waiting at all.
    Prevents it: the head's event_type CPU means running, not waiting.
  10. Q: A get_pg_wait_sampling page's pct_of_samples values add up to 55%. Is the other 45%
    unaccounted for?
    Correct: no. Those are samples from series that did not make this page's cap. The denominator is
    the window's total_samples, not the page's own sum.
    Prevents it: the head's SHARES ARE OF THE WINDOW, NOT OF THE PAGE: pct_of_samples divides by total_samples, not the page sum.
  11. Q: Someone calls get_pg_logging_audit against a SQL Server target. Will it audit that server's
    error log settings?
    Correct: no. The tool is PostgreSQL-only.
    Prevents it: the head's trailing PostgreSQL-only.
  12. Q: get_pg_io_stats is called with limit=3 on a server with 50 active combinations. Do those
    three rows represent the whole window's I/O?
    Correct: no. combinations_returned/truncated say whether more exist. The window totals cover
    every combination, not only the page.
    Prevents it: the head's THE PAGE IS BOUNDED BY limit: combinations_returned/truncated.

Test plan

  • dotnet build Darling/Darling.Tests/Darling.Tests.csproj -c Debug: build succeeded, 0 warnings, 0 errors.
  • Targeted classes (McpToolsListBudgetTests, McpToolGuideHeadsPgB*, DarlingMcpPgLoggingAuditToolsTests,
    PgWaitInstrumentDisclosureTests, McpPageContractTests, DarlingMcpPgIoToolsTests, McpToolGuideTests):
    Total 116, Errors 0, Failed 0.
  • Dropped-sentence check (dropcheck.py origin/dev HEAD get_pg_logging_audit get_pg_io_stats get_pg_wait_sampling): all three show missing=0.
  • Full Darling.Tests suite, run by the coordinator after the lane: Total 13254, Errors 0, Failed 0,
    Skipped 631 (the live-PostgreSQL classes).
  • Plain English checker: ran python C:/Users/edarl/.claude/skills/plain-english/check.py against this
    body and fixed every real hit. The remaining hits are the allowed D9 labels.
  • Live-PostgreSQL classes did not run. There is no rig in this worktree. They skip cleanly without
    DARLING_TEST_PG set, which is expected per the common brief.

Coordinator verification

  • origin/dev was already merged into the branch. The shared checkout was clean.
  • dropcheck: missing=0 for all three tools. The one D4 removal is the (#3601/#3602/#3603) list.
  • D9: a fresh Haiku agent read only the served text of these three tools and answered the 12 traps.
    All 12 answers were correct. Two answers (Q3, Q5) said "not stated" but cited the right head phrase, so
    they are not misreads.
  • Full Darling.Tests suite: Total 13254, Failed 0, Skipped 631.
  • The Lite suite was not run for this PR. The PR changes no Lite file and no PerformanceMonitor.Common
    file. CI runs the Lite suite anyway.
  • DarlingMcpPgLoggingAuditToolsTests.cs shows as a whole-file change. On dev, that file was stored with
    CRLF line endings, and one line ended in CR CR LF. This PR stores it with LF, as .gitattributes
    (* text=auto eol=crlf) expects. The content change is 29 lines added and 11 removed
    (git diff --ignore-cr-at-eol).
  • The limit parameter was reworded rather than moved to the tail. Every fact stayed: the page bound,
    reading truncated, and shares of the whole window.

Handoff

  • The coordinator ran the full Darling.Tests suite. See Coordinator verification.
  • Nothing else was deferred. The D4 removal, the D2 parameter trim, and every pin re-point are done in this
    PR, not deferred. No new issue was filed.

…g guidance off tools/list (#3898)

Refs #3898. Splits each description at the <<GUIDE>> marker: tools/list now
serves a short head (546-610 served chars, down from 2,032-2,086) plus the
get_tool_guide pointer, and get_tool_guide serves the full original prose
as the tail. No sentence dropped; D4 removed one issue-ref parenthetical
from get_pg_logging_audit's wire text (kept in this commit message instead).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014nCo36doEcUWapnXbJvY7L
@erikdarlingdata
erikdarlingdata marked this pull request as ready for review September 23, 2026 21:56
@erikdarlingdata
erikdarlingdata enabled auto-merge (squash) September 23, 2026 21:56
@erikdarlingdata
erikdarlingdata merged commit dc3b3b3 into dev Sep 23, 2026
17 of 18 checks passed
@erikdarlingdata
erikdarlingdata deleted the feature/3898-content-pg-audit-io branch September 23, 2026 21:58
erikdarlingdata added a commit that referenced this pull request Sep 24, 2026
* Add 48 buffered CHANGELOG entries in one splice

Adds 48 entries and 48 link refs (#4057, #4077, #4079, #4081, #4082, #4083, #4084, #4085, #4086, #4087, #4088, #4089, #4090, #4091, #4092, #4093, #4095, #4096, #4099, #4100, #4101, #4103, #4105, #4106, #4107, #4108, #4109, #4110, #4111, #4113, #4114, #4115, #4116, #4117, #4118, #4119, #4120, #4121, #4122, #4123, #4124, #4125, #4126, #4127, #4131, #4133, #4136, #4141). Each PR's entry was buffered, and this lands every entry whose PR was merged on origin/dev when it ran.

Entries found under a bare section line (none unless the old script ran again) move into the matching ### section, below the new entries.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QQh8LczP1HGLXQYAx4oTZC

* Changelog splice: add #4137's entry, which merged before the splice but was missed

#4137 (pg_plan_capture reads csvlog) merged at 05:57Z with a CHANGELOG entry section in its
body. It was neither spliced nor listed as needing no entry. Its entry goes under Fixed, right
after #4136's, and #4136's last sentence now points to it instead of saying plan capture is
unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NUU29PuGg9TUFBsACgZg2K

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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