Repository navigation
audit_config answers a PostgreSQL target with its own settings: the CONFIG_PG_* facts projected into the same recommendations shape, engine in place of edition, and the two checkpointing knobs marked not applicable on Aurora (#3691 line 70) - #3867
Merged
Merged
Conversation
audit_config's PostgreSQL arm has to tell an operator WHICH setting a fact is about, and "CONFIG_PG_RANDOM_PAGE_COST" is not a thing anyone types into ALTER SYSTEM. ConfigPgSettingName maps every declared CONFIG_PG_* constant to its pg_settings name, beside the constants rather than inside the tool, so a second reader of the same facts inherits the map instead of inventing it and a renamed key fails to compile in both places at once. The three keys that are not one setting are spelled so the reader cannot mistake them for a pg_settings row to go read: the extension's absence is shared_preload_libraries (pg_stat_statements), the composition check is the arithmetic it performs, and the per-table reloption says reloption (the TABLE rides the fact's ObjectName). An unknown key returns null and the caller renders the key itself: a vocabulary a reader can look up beats a guessed instruction.
… redirect #3542 stopped this tool telling a PostgreSQL operator that the config collector may not have run yet, by refusing honestly and naming where the checks live. It left the reader one hop short: the CONFIG_PG_* facts it pointed at are emitted by the very pass audit_config already runs, so a reader who asked the right question was sent to ask it again somewhere else. Erik ruled the projection in on 2026-09-22; this is it. Every difference from the SQL Server envelope is a difference of the engine, and each is now in the tool's description so the contract changes once: engine in place of edition (PostgreSQL ships no editions), a STRING current_value because 'random_page_cost 4.0', 'shared_buffers 4 GB' and 'autovacuum off' are not integers, and no suggested_value at all - the right value for a PostgreSQL knob is host- and workload-specific, so the advice's remediation sentence carries the evidence and the counter-objective a bare number would strip. The tool grades nothing. Severity is the pass's, read off the fact and spelled ok / review / warning, plus not_applicable for a fact the collector stamped: checkpoint_timeout and max_wal_size on Aurora, where the storage layer owns checkpointing. Those rows report the engine's own sentence - lane 15 composed it into the advice block, so no special case is needed here - are counted on their own summary line, and are excluded from settings_checked, because a knob the engine does not consult was not checked and counting it would inflate the audit's idea of how much it looked at. Facts are filtered by KEY prefix, not by source: the family lives on pg_config, pg_memory (the composition check) and pg_vacuum (the per-table reloption), so a source filter would silently drop the two checks that are not settings snapshots. PgConfigRecommendation is a separate record from ConfigRecommendation rather than a widening of it, so the SQL Server arm's payload stays byte-identical.
Rider 2 of Erik's ruling: the description contract changes ONCE, so the residual edition-awareness drift goes out with the projection rather than in a later pass. The A15/A16 fix landed in #3653 and its pin passes; what was left were three doc comments that had not moved. Both SKUs' memory collectors claimed their facts 'enable edition-aware memory recommendations in the config audit'. They enable RESOURCE-based ones: max server memory is sized against the host's physical RAM, and no check in that audit branches on the edition - the payload reports it for context, which is the exact distinction the tool's own description has made since #3653. Lite's schema comment called the v2 server-metadata columns 'edition-aware analysis' and now names what they are: the columns the config audit reads, reported for context. The instruction table's audit_config row and the step-7 mention now describe the PostgreSQL arm as a projection rather than a refusal, one sentence each, matching the tool description word for word on the three things that differ (engine in place of edition, unit-carrying current_value with no suggested_value, and not_applicable on Aurora). Lite's audit_config body is untouched and needs no description change: it has no PostgreSQL targets by product and its description never carried the refusal sentence, so there was nothing there to keep or correct.
This was referenced Sep 22, 2026
erikdarlingdata
added a commit
that referenced
this pull request
Sep 22, 2026
…t at the tool that renders it (#3868) (#3874) Lane 15 of #3691 (#3728) taught the write family to tell Aurora the truth, and it stamped one knob. CONFIG_PG_MAX_WAL_SIZE carries not_applicable / not_applicable_on_aurora on an aurora-postgres target because the calibration read fifty clusters over fourteen days and found sixty timed "checkpoints" an hour with a requested share of 0 on every one: Aurora's storage layer owns checkpointing, so max_wal_size at its shipped default is not a convention finding there, it is the parameter group's value for a knob the engine does not consult. Its sibling, CONFIG_PG_CHECKPOINT_TIMEOUT, came out of the same method in the same pass unqualified. That is what #3867 found while pinning rider 1 of Erik's ruling, and it fixed the symptom it could reach: audit_config renders both checkpointing knobs not_applicable on Aurora, the second through an engine-side arm in the tool. The rider is satisfied for that one surface. Everything else that reads the fact -- get_analysis_facts, the story walk, the drill-downs -- still read a graded, unqualified fact, and its composed advice still ended with "tune it with max_wal_size, not instead of it," which on Aurora sends an operator to a knob the storage layer ignores. Belt, not braces: the fact is the truth the rest of the engine reads, and it disagreed with the tool. The stamp is mirrored, not invented. PgTargetFactCollector.Config.cs now stamps checkpoint_timeout the way it stamps max_wal_size, in the same method, off the same single read: the is_aurora flag on the SERVER_MAJOR_VERSION registry fact emitted just before this method, which comes from MonitoredEngineKind and never from a column's presence (#2530). The value is still emitted -- what a parameter group holds for a knob nothing reads is a fact about the parameter group and worth seeing, and the write partial reads checkpoint_timeout_s off max_wal_size's metadata regardless. PgTargetScorer.Config.cs needed no change and got none: its not_applicable read already returns 0 for a stamped fact, as it has for the sibling since lane 15, so no advisory roots and FactScorer.ScoreAll skips amplifiers at base 0. This knob was base 0 anyway; the stamp is about what the fact SAYS. One line had to move. audit_config keeps its engine-side arm, now honestly commented as belt and braces -- one read of a flag that is already true, kept because this tool is where rider 1's guarantee is made to a reader. But the tool also APPENDS the Aurora sentence to checkpoint_timeout's recommendation, and that append was gated on the fact being UNSTAMPED. That gate was correct when only the engine knew. Stamping the fact would have silently stopped appending the one sentence the rider exists to guarantee -- a fix that quietly regressed #3867's own acceptance, with a green build. The gate now discriminates by KEY: max_wal_size's composed block carries lane 15's not-applicable sentence inline and needs no append, while checkpoint_timeout's block is the base-0 context one with no Aurora arm, so the sentence is appended there. Found by reading #3867's live pins before running them. The write family's Aurora e2e now pins the pair where it pinned one: through the real get_analysis_facts, checkpoint_timeout reads 300 s with base 0 and both metadata flags set, beside the existing max_wal_size assertions, so a future edit that stamps only one knob again fails a test instead of shipping. PgTargetAuditConfigTests (#3867, two live arms) is untouched and green, which is the evidence that the surface did not move while the fact underneath it changed. Both config-family lineage censuses were run for lane 15's not_applicable-stamps-no-lineage contract and needed no exemption: they walk scorer SOURCE for lineage markers rather than counting facts per family, and this lane adds no bar and stamps no threshold_lineage. Verified against a live timescaledb-pg18 store: PgTargetAuditConfigTests 2/2, PgTargetWriteTests 29/29, PgTargetKnobsTests 43 (1 skipped), PgTargetThresholdLineageTests 4/4, PgTargetMeasuredLineageTests 4/4, plus PgTargetFactCollectorTests 8/8, DarlingMcpToolsTests 16/16, McpPayloadContractCensusTests 67/67, PgTargetSharedSwitchRoutingTests 28/28 and RepoFileAdoptionTests 2/2. Zero warnings. Closes #3868. Co-authored-by: erikdarlingdata <erik@erikdarling.com>
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.
What a PostgreSQL operator now learns
audit_configon a PostgreSQL target used to answer an honest refusal: this tool evaluates SQL Server settings, go callget_analysis_factswith sourcepg_config. True, and useless — the caller had already asked the right question of the right server, and was sent to a different tool to ask it again. This lane projects the analysis pass'sCONFIG_PG_*facts into the samerecommendationsshape the SQL Server arm returns, so one call answers "how is this server configured, and what about it is worth looking at."PARTIAL for #3691 — do not close. The checklist line completed, verbatim:
Erik's ruling (2026-09-22 02:23Z): YES, with two riders, both landed here:
CONFIG_PG_CHECKPOINT_TIMEOUTandCONFIG_PG_MAX_WAL_SIZErenderstatus = not_applicableonaurora-postgres, counted on their own summary line and excluded fromsettings_checked— a knob the engine does not consult was not checked, and folding it into that count would have the audit overstate what it looked at. Neither is ever a finding.PgFactCollector.Resources.cs, Lite'sDuckDbFactCollector.Resources.cs,AnalysisSchema.csv2) — all three now say resource-based / the server-metadata columns the config audit reads, which is what those facts and columns actually enable.The description, before and after
The first four sentences are unchanged (including "NO check branches on it"). Only the trailing sentence moved:
Before:
SQL Server only: for a PostgreSQL target this tool refuses with status not_collected and points at get_pg_server_config, get_pg_logging_audit and the CONFIG_PG_* facts instead of pretending the collector failed.After:
For a PostgreSQL target it projects the analysis pass's CONFIG_PG_* setting facts into the same recommendations shape (setting, current_value with unit, status, recommendation; no suggested_value - the recommendation sentence carries the evidence), reports engine in place of edition, and renders checkpoint_timeout / max_wal_size as not_applicable on Aurora, where the engine manages checkpointing. get_analysis_facts has each setting's full investigation; get_pg_server_config has the raw snapshot.The instruction table row (
DarlingMcpInstructions.cs:99) and the step-7 mention (:340) were updated to match in one sentence each.What the payload says, and why each difference from the SQL Server arm exists
Every difference is a difference of the engine, and each is stated in the description so the contract changes once:
enginein place ofedition— PostgreSQL ships no editions. The token is the registry's (postgres/aurora-postgres), resolved per call offservers.engine_kindthroughMonitoredEngineKind, never inferred from a column's presence (PostgreSQL targets have no UI on either SKU, and both UIs render SQL Server tabs at them #2530).editionis absent, not null: a PostgreSQL payload carrying"edition": nullwould be the same false edition-awareness Brains-review campaign: deferred structural residue (from #3538 / #3539 / #3540 / #3541) #3653 took out of the description.current_valueis a STRING with its unit — the SQL Server arm'sintcannot carryrandom_page_cost 1.1,shared_buffers 128 MB,checkpoint_timeout 5 minortrack_io_timing on. Formatted off the FACT KEY, never sniffed from the magnitude (4 could be a cost ratio or four megabytes; 300 could be seconds or connections), in the same shapesPgTargetAdvice's privateKnob*formatters render inside an advice sentence — so one value does not read two ways across two surfaces.suggested_value, at any depth — the right value for a PostgreSQL knob is host- and workload-specific. The advice's remediation sentence carries the evidence and the counter-objective a bare number would strip, which is precisely what the evidence-first discipline forbids shipping.recommendationis the advice headline + remediation; investigation stays inget_analysis_facts, and the description says so.threshold_lineageisnull, not0— the config family stamps no lineage because its bars ARE PostgreSQL's own shipped defaults; there is no chosen number to disclose (PgTargetScorer.Configsays exactly this in its class summary).0would claim a bar had been chosen unmeasured.object_nameis OMITTED on a server-level row, present only where the fact carries one (CONFIG_PG_AUTOVACUUM_DISABLEDis a per-table reloption). A null table name on ashared_buffersrow invites a reader to wonder which table it meant.The tool grades nothing: severity is the pass's, read off the fact, and this arm only spells it
ok/review/warning/not_applicable. Facts are filtered by KEY PREFIX rather than source — the family lives onpg_config,pg_memory(CONFIG_PG_MEMORY_OVERCOMMIT) andpg_vacuum(CONFIG_PG_AUTOVACUUM_DISABLED), so a source filter would silently drop the two checks that are not settings snapshots — and iterated as an ordered LIST, because the reloption check repeats its key per table. Zero facts keeps its ownno_config_dataenvelope naming the health read: no facts is not a refusal.PgTargetFactKeys.ConfigPgSettingNamemaps every declaredCONFIG_PG_*key to thepg_settingsrow an operator would go set, beside the constants so a renamed key fails to compile in both places at once. The three that are not one setting are spelled so a reader cannot mistake them for a row they could go read:shared_preload_libraries (pg_stat_statements),shared_buffers + work_mem × max_connections (composite),autovacuum_enabled (table reloption). A bareautovacuumon the reloption row would send an operator toALTER SYSTEMfor something onlyALTER TABLEcan reach.Rider 1's second knob
The calibration stamped
not_applicableonCONFIG_PG_MAX_WAL_SIZE(lane 15, #3728 §A4) but not onCONFIG_PG_CHECKPOINT_TIMEOUT— correctly, because that fact is base-0 context there and nothing was grading it. It is graded by nothing here either, but this tool renders it as a setting with a recommendation, and the composed context sentence says tune it with max_wal_size, which on Aurora points an operator at a knob the storage layer ignores. Rider 1 names both keys for exactly that reason, so the engine-side arm lives in this tool with the reason written down. Stamping the fact itself (soget_analysis_factssaid it too) is the collector's change and lane 15's file — reported, not folded.Byte-identity
int current_value, itssuggested_value, itsedition = editionNameecho and every check are byte-identical; the projection row is a separatePgConfigRecommendationrecord rather than a widening ofConfigRecommendation, so nothing about the new shape can reach it.DarlingMcpToolsTests's existingaudit_configbody-scan assertions (the only edition reads are the fact lookup and the payload echo) run unchanged.audit_configis SQL Server-only by product (no PostgreSQL targets). Worth stating precisely: Lite's description never carried the trailing refusal sentence at all, so there was nothing there to leave in place. Its body and description are unmodified; only the two doc comments under rider 2 changed in that tree.Tests
PgTargetAuditConfigTests(new, 2 tests)pg_server_configsnapshot →AuditConfig→ JSON read:enginepresent /editionabsent, one row per fact, unit-carrying string values (128 MB,1 GB,8 GB,1.1,on,5 min), statuses off the pass's severities, nosuggested_valueanywhere in the payload text,threshold_lineagenull,object_nameomitted, summary arithmetic. Aurora arm: both checkpointing knobsnot_applicablewith lane 15's verbatim sentence and the engine-side sentence, out ofsettings_checked,shared_buffersstill gradedPgTargetSharedSwitchRoutingTests(+1 test)CONFIG_PG_*returns non-null, lower-case, and the three composites say what they are; unknown key and null → nullPgTargetMcpSurfaceTests(reworked)StartsWith(PgTargetFactKeys.ConfigPrefix(the CONSTANT, not the literal), no source filter, andnot_collected/get_pg_logging_auditgone from the whole tool bodyDarlingMcpToolsTests(renamed)…_AndNamesThePostgresProjection: the four stated differences in the tool's own words, plus the refusal no longer promised; "NO check branches" and the body-scan edition assertions unchangedMcpPayloadContractCensusTestsnot_applicableadded toaudit_config's status-vocabulary roster line with its reasonTsqlConventionGuardTestsToPayloadregistered inKnownTruncatedRangeswith what falls outside the range and why no census reads it thereDocCommentHygieneTests/RepoFileAdoptionTests/ServerPageTabsTests/ViewTemplatesTests/PgTargetKnobsTestsHarness: net10.0,
AssemblyName=Darling.Tests, inside the worktree, against a throwawaytimescale/timescaledb:2.28.1-pg18(Docker contextdesktop-linux); torn down, harness deleted before commit. The fullDarling.Testsproject builds withEnableWindowsTargeting=true(no new warnings).Self-review — three riskiest hunks
not_applicablearm (DarlingMcpTools.cs) — it makes this tool say something the FACT does not, which is the shape of an inconsistency between two surfaces. Held by the live Aurora arm asserting the appended sentence's exact text and the stock arm assertingcheckpoint_timeoutreadsokthere; the comment states that the fact-side stamp is lane 15's file, not a fold-in.FormatConfigPgValue's two inversions —CONFIG_PG_AUTOVACUUM_OFFis a finding FLAG (value 1 = the setting isoff), andCONFIG_PG_AUTOVACUUM_DISABLED's value is the table's backlog ratio, not its reloption. Both are documented at the method and the shapes a reader would get backwards are pinned by the live stock arm's six rendered values.ToPayloadternary — the only place a key can silently go missing (two anonymous initializers, one per arm). The live pins read both arms' keys from serialized JSON, and the member-scan roster entry names exactly what falls outside the walker's range.Reviewer checklist
ConfigRecommendationuntouched).settings_checkedexcludesnot_applicable;not_applicableis its own summary line.threshold_lineageis null (absent bar), never 0, on config rows.suggested_valuereaches the wire on the PostgreSQL arm.CONFIG_PG_*constant names a setting (census fails on a new key).What it does not do
No change to which
CONFIG_PG_*facts exist or to any bar; no migration rung; noget_pg_server_configchange; Lite'saudit_configbody untouched; no Viewer change; CHANGELOG buffered, not edited.Out-of-lane (issue-class, reported not folded)
CONFIG_PG_CHECKPOINT_TIMEOUTis not stampednot_applicableon Aurora at the COLLECTOR, soget_analysis_factsstill shows it unqualified there. Crossing into lane 15's collector file + its calibration pins is a cross-lane edit; this lane made the operator-facing surface true and left the fact where it is.