Repository navigation
[BUG] Registration-time collision check: refuse a new registration whose host + actual database matches an existing one #2280
Description
Activity
- added 6 commits that reference this issue
on Aug 15, 2026 Fixed in #2283, merged to
dev.add_serversnow refuses a registration whose connection lands in a database another registration already covers. The probe already ran in-process at Add, and since #2277 it returns the database the connection actually reached — so the answer was in hand at exactly the moment the decision had to be made.Keyed on the full identity, which is what keeps the two legitimate pairs working: a read-only-intent registration alongside its read-write twin for one database, and a PostgreSQL instance alongside a SQL Server on one host. Silent when the probe reports no database (unknown is not colliding) and when the entry reaches the database it names (already ruled on by the declared-duplicate gate).
It also fixed a regression #2218 had introduced in this same method, which turned out to be the more urgent half. The duplicate gate built its key from host, database and read-only intent only — the 3-argument form — so once engine and port joined the identity the gate was keying on a narrower identity than the store derives. A PostgreSQL instance on a host that already had a SQL Server registration read as a duplicate and was refused: a valid pair rejected because the gate could not see what distinguished them.
ExistingServersSqldid not even select the columns, so there was nothing to notice; it compiled and every existing test passed. It now readsengine, portand has an explicit pin that also asserts the two identities genuinely differ, so the columns cannot quietly become decorative.Two things from scoping that are recorded on the method rather than left to be rediscovered:
- The file seed keeps the tripwire only. A server silently unmonitored because of a collision at service start is worse than one collected twice with a loud log, and refusing there is a startup-time decision nobody is present to see.
- The honest limit: existing rows record only the database they declare, so this catches "the new one lands where an existing one lives" and not "both mis-resolve to a database neither names". Closing that needs the actual database persisted per row; Trip when a registration is connected to a database it does not name (#2228) #2277's tripwire reports it at connect for both in the meantime.
- added a commit that references this issue
on Sep 18, 2026
Split out of #2228, whose sweep-time tripwire shipped in #2277. That issue's core assertion — "no
DB_NAME()cross-check exists" — is no longer true; this is layer 2 of the fix shape it proposed.What is still wrong
Nothing stops a NEW registration being created for a host + database that an existing registration already resolves to. The tripwire in #2277 will notice at connect and log loudly, but only after the registration exists and has begun collecting — so the duplicate history it warns about has already started accumulating under a second identity.
The fix shape, from #2228
Why it is more than the tripwire moved earlier
The check needs the actual database, which only the target can answer — so registration has to connect before it can decide. That is reached three different ways, and they do not share a path:
add_servers(MCP) already does an in-process connection probe, so this is the cheapest of the three to wire.darling.jsonseed runs before any connection exists, at service start, for every server at once. Refusing there is a different question — it would mean a server silently not being monitored because of a collision, which is worse than collecting it twice with a loud log.That asymmetry is worth settling before implementing: the honest answer may be that the seed keeps the tripwire only, and the two interactive paths refuse.
Also unresolved, from the same investigation
Whether an override is needed at all. Two registrations deliberately pointing at one database is not obviously useful — but a read-only-intent registration alongside a read-write one for the same database IS legitimate, and
read_only_intentis already part of the identity, so the check must compare on the full identity rather than on (host, database) alone or it will refuse that valid pair.