Skip to content

fix(db,ui,docs): a refusal drawn as a measurement, in five places - #515

Merged
cevheri merged 3 commits into
mainfrom
chore/backlog-round17
Aug 27, 2026
Merged

fix(db,ui,docs): a refusal drawn as a measurement, in five places#515
cevheri merged 3 commits into
mainfrom
chore/backlog-round17

Conversation

@cevheri

@cevheri cevheri commented Aug 27, 2026

Copy link
Copy Markdown
Member

Round 17. Five backlog entries close, seven open in their place. Every closed one is the same defect in
different clothes: a reading that could not be taken, or a list that was cut, reaching a reader as a
confident figure.
The absence rule (#477) is house law here; these are the places it was not applied.

What closes

D40 — the Overview panel's connection count. DatabaseOverview.activeConnections is optional for the
reason its docblock gives, and SQL Server, Oracle and MongoDB each initialised a local to 0 and
swallowed the read's failure into it. A denied VIEW SERVER PERFORMANCE STATE, an unprivileged
V$SESSION or a serverStatus with no connections section drew a confident 0 connections on a
server with plenty. All three now omit the key; a real zero still reads as zero; both arms pinned per
provider.

The existing SQL Server test was asserting the fabrication rather than a measurement:
expect(typeof overview.activeConnections).toBe("number") passed because the fabricated 0 is a
number. Its purpose-built fixture was dead code — shadowed by a generic branch matching the same
statement — so the assertion had never once seen the value it was written for.

D41 — two surfaces reading a cap as a count. The Queries tab's Queries card summed the calls of a
list every provider caps at ten and labelled it the database's query count; Slow was bounded by ten
however many slow statements the server held. Measured against a MySQL server holding 59 digests for one
schema, both cards were the ceiling wearing a measurement's label. On the provider side
TRINO_MAX_STATS_TABLES cut the table-stats read inside the provider, where no marker above it could
see the cut; it now refuses rather than truncating, and the refusal names the real count.

D36 — the migration generator emitted DDL SQLite cannot parse. ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY is a syntax error on SQLite wherever the file is run. There were two emission sites, not
the one the entry described: the ALTER path, and — undocumented — generateCreateTable, which writes a
new table's foreign keys as a separate ALTER. libSQL had the same defect there, so its earlier fix was
incomplete. The two sites want different answers: in the CREATE path the key belongs inside the
CREATE TABLE, where SQLite accepts it and nothing is lost; in the ALTER path it cannot be expressed and
is declined with a comment naming table recreation.

D38 — getConnectionInfo masked an authority password and nothing else, so a libSQL string carrying
its whole token as ?authToken= was returned in the clear. The mask now covers the authority and the
value of every credential-shaped parameter, in any position. Two review rounds then found two more shapes
in the fix itself: a credential leading an ADO-style string was returned verbatim, and narrowing the
authority pattern had stopped masking postgres://user:p/w@host/db, which the old one masked.

That second one is covered rather than hidden. postgres://host:5432/tenant@acme has the identical
shape and holds no secret, so masking one masks the other — and drawing *** over a port asserts a
credential the string never carried, a fabricated reading, which this rule forbids more strongly than it
forbids the miss. The docblock says so and the test file pins the gap, so it is visible rather than
assumed closed. D42 carries the parse-based fix.

U23 — the Storage tab labelled its remainder "Other (TOAST, FSM)" on every engine. TOAST and the free
space map are PostgreSQL structures; SQLite, libSQL, MySQL, Oracle, SQL Server, ClickHouse and the HTTP
engines have neither.

Two defects found in the same files while fixing those

  • The Storage tab was the third reader of errors.tables and the only one that did not read it. A
    refused table read arrived as an empty list, every() was vacuously true, and the tab drew a measured
    0 B for Tables and Indexes with the remainder absorbing the whole database at 100%. It now carries the
    engine's own sentence, the way its two sibling panels already do, while a genuinely empty database still
    reads 0 B.
  • Quick Stats published three cap-bounded figures as counts — "Slow Queries" off a list capped at 10,
    and "Active" and "Idle" off one list capped at 50 which the two badges split while reading as the
    server's totals. All three now name the rows they measure. (The review found one of the three.)

MongoDB's getOverview had a second fabricated zero beside the first: databaseSizeBytes is optional
for the same stated reason, and the Storage tab keys its entire breakdown off whether that key is present.
So a denied serverStatus did not hide a number — it replaced an honest refusal with a breakdown over a
zero-byte database, and with the table read still answering the remainder went negative, which
formatBytes renders as the literal string NaN undefined. The success path had the same shape
through || 0, and so did getHealth, whose databaseSize string is the one the agent forwards to the
model verbatim.

A new guard: provider docs cite code by name, not by line

A line number hand-copied into prose has nothing measuring it. The eight seam rows in both search docs
were stale at birth: they entered in one commit (25712e68, #429) as 751/811/831/844/860/873/884/898
while that same commit's declarations sat at 808/868/888/901/917/930/941/955 — a uniform +57, which is
exactly why nobody noticed. The rows stayed in ascending order and read as a consistent, plausible list.
Today the offset is +65. docs/providers/redis.md shows what correcting such a number buys: :102 (#89,
true then) → :99 (#122, true then) → rotted again.

tests/unit/provider-docs-monitoring-citations.test.ts bans the form, so a correct line number fails
it too, and its scope statement names what is not measured yet rather than implying coverage. Corpus
measurement: of 69 machine-checkable citations, 68 were stale; 18 are fixed here; DOC4 carries the
remaining 62, all 62 stale.

What opens

ID Why it is an entry and not part of this PR
D42 The mask cannot cover an authority password holding a character RFC 3986 reserves — the colliding shape holds no secret. The fix is parsing, not a better pattern.
D43 SQLite gained ALTER COLUMN ... SET/DROP NOT NULL in 3.53.0 (measured: it rewrites the stored schema and is enforced on insert). The generator cannot simply emit it — sqld ships 3.47.0, and sqlite runs on whichever SQLite its runtime bundles, so a migration file would run on one deployment and fail on another.
D44 databaseSizeBytes is fabricated as 0 wherever the size is unknown, in 14 of 16 type-ids. Cassandra's own comment is the precedent and states the argument. 14 provider files, 14 docs, 14 test files.
D45 On SQL Server 2019 and earlier the count is under-reported, not refused: Microsoft documents sys.dm_exec_sessions as row-filtered, and sys.configurations as needing only public below 2022, so the statement succeeds and returns the caller's own session. Distinguishing that needs a permission probe and a live instance with an ungranted login.
D46 One fabricated connection zero survives the sweep, in the shared search provider. Three of the five comments citing the old encoding are now false and are corrected here; two remain true — for maxConnections zero and absence really are one fact, which is what Druid and Trino cite. Moving the encoding is the entry.
U24 A measured zero total draws the Storage remainder bar full, and the same zero puts NaN undefined in the cell beside it. A refused overview also drops the engine's sentence in a file that carries it for two other panels.
DOC4 62 stale line citations over 12 docs; the 209 non-checkable ones are named as unmeasured rather than assumed.

Verification

Gates on the pushed tree: format clean · lint 0 errors / 132 pre-existing warnings · typecheck
clean · knip clean · bun run test all 33 groups pass · bun run build exit 0 · merged coverage
44382/44382 lines (100.00%).

Mutation-tested, not just green. Every lane was required to corrupt the line its test pins, confirm
red, and restore byte-for-byte. Highlights:

  • The redaction's two fixes: dropping ^ from the parameter pattern reddens 4 tests; reverting the
    authority anchor reddens 2.
  • The Storage absence fix carries an over-fix guard: setting statsRefused = tables.length === 0
    reddens the measured-empty control arm, so the fix cannot degenerate into "N/A whenever the list is
    empty".
  • The citation guard was mutated six ways, including reinstating a correct line number (still red —
    the form is what is banned) and renaming the cited declaration in the source.

Driven in real Chrome against the embedded SQLite sample (796 KB, 6 tables) — the engine U23 is about:

Check Result
TOAST / FSM anywhere on the page absent
Remainder label, both breakpoints Other (unattributed) / Other
Breakdown arithmetic 504 KB + 288 KB + 4 KB = 796 KB, remainder bar translateX(-99.4975%)
NaN / undefined in the DOM absent
Quick Stats labels Listed slow queries, Active of listed sessions, Idle of listed sessions
Queries tab the cap-labelled total card is gone; SQLite refuses with its own sentence, not zeros
Application console errors 0 (the two 404s in the log are my own manual fetch probes of paths that do not exist)

Engine claims checked against the vendors' own documentation, not memory: Microsoft Learn for
sys.dm_exec_sessions and sys.configurations permissions (quoted verbatim in D45), the MongoDB manual
for serverStatus and dbStats, and SQLite itself via bun:sqlite 3.53.0 for the ALTER TABLE
repertoire.

Findings I verified and did not adopt

  • A review claimed the seam table had been "hand-corrected in one row in a past round, leaving an internal
    contradiction". git log -S"index.ts:811" returns one commit and the numbers went in monotonic, so
    no committed state ever contradicted itself. The single-row refresh existed only in this round's
    uncommitted tree and would never have appeared in history. The guard's docblock now states the true
    mechanism, which turned out to be stronger: the numbers were wrong the day they were written.
  • A review suggested extending the guard to mongodb.md and oracle.md was "a two-line change". Those
    docs still hold 14 and 16 line citations, and the guard asserts no line numbers anywhere, so adding
    them would fail immediately. They are named in DOC4 instead.
  • Blanket-repointing the five comments that cite mssql.ts for the "0 means not published" encoding would
    have made two of them false: for maxConnections, 0 and absence are one fact. Only the three about
    activeConnections are corrected.
  • A derived claim that the negative remainder renders -1536 B was wrong in its detail — formatBytes
    takes Math.log of a negative, so it renders NaN undefined. Worse than claimed; corrected in both the
    doc and the code comment, and folded into U24.

Rebased onto main after #514; base tree verified identical to the squash, so nothing was resurrected.

cevheri added a commit that referenced this pull request Aug 27, 2026
Deleting an entry leaves every bare id that cited it pointing at nothing. This is the third
round in a row where that happened, and T4 in the backlog is the standing record of the
class, so the repointing is part of the same PR rather than a follow-up.

Nineteen citations across 13 files now name #515, the PR that closed the work, which a
reader can actually open. They were spread across code comments (the migration generator,
the Trino introspection pair, three monitoring tabs), one provider doc and seven test files.

One is deliberately left alone. `tests/unit/backlog-structure.test.ts` says "main carried
D36, D37 and D38 twice", which is a statement about what happened in #511 and #513, not a
citation of an entry. It is still true, and D37 is still an open entry, so repointing it
would have made a correct sentence wrong - the same trap as blanket-repointing the five
comments about the "0 means not published" encoding, two of which describe `maxConnections`
and remain correct.
Five backlog entries close. Every one is the same defect wearing different clothes: a
reading that could not be taken, or a list that was cut, reaching a reader as a confident
figure. The absence rule (#477) is house law here, and these are the places it was not
applied.

D40 - the Overview panel's connection count. `DatabaseOverview.activeConnections` is
optional for the reason its docblock gives, and SQL Server, Oracle and MongoDB all
initialised a local to 0 and swallowed the read's failure into it. So a denied
VIEW SERVER PERFORMANCE STATE, an unprivileged V$SESSION or a serverStatus without a
connections section drew a confident "0 connections" on a server with plenty. All three now
omit the key, and a real zero still reads as zero - both arms pinned per provider.

The existing SQL Server test was asserting the fabrication rather than a measurement:
`expect(typeof overview.activeConnections).toBe("number")` passed because the fabricated 0
is a number. Its purpose-built fixture was dead code, shadowed by a generic branch that
matched the same statement, so the assertion had never seen the value it was written for.

D41 - two surfaces reading a cap as a count. The Queries tab's *Queries* card summed the
calls of a list every provider caps at ten and labelled it the database's query count;
*Slow* was bounded by ten however many slow statements the server held. Measured against a
MySQL server holding 59 digests for one schema, both cards were the ceiling wearing a
measurement's label. On the provider side TRINO_MAX_STATS_TABLES cut the table-stats read
inside the provider, where no marker above it could see the cut; it now refuses rather than
truncating, and its refusal names the real count.

D36 - the migration generator emitted `ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY` for
SQLite, which has no ALTER that adds a constraint, so the file was a syntax error wherever
it was run. There were two emission sites, not the one the entry described: the ALTER path
and, undocumented, `generateCreateTable`, which writes a new table's foreign keys as a
separate ALTER. libSQL had the same defect there, so its earlier fix was incomplete. The
two sites want different answers - in the CREATE path the key belongs inside the CREATE
TABLE, where SQLite accepts it and nothing is lost; in the ALTER path it cannot be
expressed and is declined with a comment naming table recreation.

D38 - `getConnectionInfo` masked `:secret@` in an authority and nothing else, so a libSQL
connection string carrying its whole token as `?authToken=` was returned in the clear. The
mask now covers the authority and the value of every credential-shaped parameter, in any
position. Two rounds of review found two more shapes in the fix itself: a credential
LEADING an ADO-style string was returned verbatim, and narrowing the authority pattern had
stopped masking `postgres://user:p/w@host/db`, which the old one masked.

What that second one cannot do is covered rather than hidden. `postgres://host:5432/tenant@acme`
has the identical shape and carries no secret, so masking one masks the other, and drawing
`***` over a port asserts a credential the string never carried - a fabricated reading, which
this rule forbids more strongly than it forbids the miss. The docblock says so and the test
file pins the gap, so it is visible rather than assumed closed. D42 carries the parse-based
fix.

U23 - the Storage tab labelled the remainder of its breakdown "Other (TOAST, FSM)" on every
engine. TOAST and the free space map are PostgreSQL structures; SQLite, libSQL, MySQL,
Oracle, SQL Server, ClickHouse and the HTTP engines have neither. On libSQL it read 4.00 KB
under that label against a real 64 KB database: the number right, the words another
engine's.

Two defects found in the same files while fixing those, both pre-existing:

- The Storage tab was the third reader of `errors.tables` and the only one that did not
  read it. A refused table read arrived as an empty list, `every()` was vacuously true, and
  the tab drew a measured 0 B for Tables and Indexes with the remainder absorbing the whole
  database at 100%. It now carries the engine's own sentence, the way its two sibling panels
  already do, while a genuinely empty database still reads 0 B.
- Quick Stats published three cap-bounded figures as counts: "Slow Queries" off a list
  capped at 10, and "Active" and "Idle" off one list capped at 50, which the two badges
  split while reading as the server's totals. All three now name the rows they measure.

MongoDB's `getOverview` had a second fabricated zero beside the first: `databaseSizeBytes`
is optional for the same stated reason, and the Storage tab keys its entire breakdown off
whether that key is present. So a denied serverStatus did not hide a number, it replaced an
honest refusal with a breakdown over a zero-byte database - and with the table read still
answering, the remainder went negative, which `formatBytes` renders as the literal string
"NaN undefined". The success path had the same shape through `|| 0`, and so did `getHealth`,
whose `databaseSize` string is the one the agent forwards to the model verbatim.

Provider docs now cite code by name rather than by line, enforced by a new guard. A line
number hand-copied into prose has nothing measuring it. The eight seam rows in both search
docs were stale at birth: they entered in one commit as 751/811/831/844/860/873/884/898
while that same commit's declarations sat at 808/868/888/901/917/930/941/955 - a uniform
+57, which is exactly why nobody noticed. The rows stayed in ascending order and read as a
consistent, plausible list. Today the offset is +65. The guard bans the form, so a correct
line number fails it too, and its scope statement names what is not measured yet rather than
implying coverage.
Deleted: D36 (the migration generator's invalid SQLite DDL), D38 (the connection-string
mask), D40 (the Overview panel's fabricated connection zero), D41 (a cap read as a count),
U23 (PostgreSQL storage vocabulary on every engine). The three section index lines are
recomputed from the surviving headings rather than edited by hand, which the structure guard
added last round now checks in both directions.

The seven that open were all measured while closing those five, and each one is here rather
than in the PR for a stated reason:

D42 - the mask cannot cover an authority password holding a character RFC 3986 reserves,
because `postgres://host:5432/tenant@acme` has the identical shape and holds no secret. The
fix is parsing, not a better pattern.

D43 - SQLite gained `ALTER COLUMN ... SET/DROP NOT NULL` in 3.53.0, measured on 3.53.0:
it rewrites the stored schema and is enforced on insert. The generator declines it on both
ids. It cannot simply stop: sqld ships 3.47.0, and the `sqlite` provider runs on whichever
SQLite its runtime bundles, so a migration file handed to a human would run on one
deployment and fail on another.

D44 - `databaseSizeBytes` is fabricated as 0 wherever the size is unknown, in 14 of 16
type-ids, and the Storage tab keys its whole breakdown off whether the key is present.
Cassandra's own comment is the precedent and states the argument. 14 provider files, 14
docs, 14 test files, which is why it is an entry.

D45 - on SQL Server 2019 and earlier the connection count is under-reported rather than
refused. Microsoft documents `sys.dm_exec_sessions` as row-filtered, not refused, and
`sys.configurations` as needing only `public` below 2022, so the statement SUCCEEDS and
returns the caller's own session. Distinguishing that needs a permission probe and a live
instance with an ungranted login.

D46 - one fabricated connection zero survives the sweep, in the shared search provider, and
three of the five comments citing the old encoding are now false while two remain true: for
`maxConnections` zero and absence really are one fact, which is what Druid and Trino cite.
The three false ones are corrected here; moving the encoding is the entry.

U24 - two absences the Storage tab still renders as measurements: a measured zero total
draws the remainder bar full, and the same zero puts the literal string "NaN undefined" in
the cell beside it, because `formatBytes` takes `Math.log` of a negative. A refused overview
also drops the engine's sentence in a file that carries it for two other panels.

DOC4 - 62 line citations remain in the provider docs and every checkable one is stale: of
69 machine-checkable before this round, 68 were wrong; after 18 fixes, 62 remain and all 62
are wrong, over 12 docs. The other 209 point at expressions and table rows, so no heuristic
can judge them and no figure is claimed for them.
Deleting an entry leaves every bare id that cited it pointing at nothing. This is the third
round in a row where that happened, and T4 in the backlog is the standing record of the
class, so the repointing is part of the same PR rather than a follow-up.

Nineteen citations across 13 files now name #515, the PR that closed the work, which a
reader can actually open. They were spread across code comments (the migration generator,
the Trino introspection pair, three monitoring tabs), one provider doc and seven test files.

One is deliberately left alone. `tests/unit/backlog-structure.test.ts` says "main carried
D36, D37 and D38 twice", which is a statement about what happened in #511 and #513, not a
citation of an entry. It is still true, and D37 is still an open entry, so repointing it
would have made a correct sentence wrong - the same trap as blanket-repointing the five
comments about the "0 means not published" encoding, two of which describe `maxConnections`
and remain correct.
@cevheri
cevheri force-pushed the chore/backlog-round17 branch from b6c7432 to 51f74cf Compare August 27, 2026 14:42
@sonarqubecloud

Copy link
Copy Markdown

@cevheri
cevheri merged commit d88d75b into main Aug 27, 2026
19 checks passed
@cevheri
cevheri deleted the chore/backlog-round17 branch August 27, 2026 15:57
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