A provision names the engine, because a consumer is coupled to one

Provisions were named after roles: provides "database", requires
"database". Nothing distinguished engines, so a module written against
PostgreSQL could be matched to a provider of SQL Server, resolve as
satisfied, deploy, and fail on its first query — with nothing
connecting that error back to a match made elsewhere by something that
believed it had done its job.

The failure is in the direction that hides. Refusing on ambiguity
exists precisely so this does not happen, and the generic name walked
around it: with one provider of each name nothing is ambiguous, so
nothing is asked.

How it got in: every resolver test had exactly one provider per name,
so no mismatch was expressible and none was caught. The fixtures agreed
with the design — the same fault as the imagined test output in
04-ISSUES/005, at the level of a name.

Refused rather than documented, because the old naming *was* the
documented convention. Providing database/db/sql/sql-database is now a
parse error naming what to write instead.

The rule is about coupling, not specificity everywhere: route and
resolver stay role-named, because a consumer genuinely cannot tell
which proxy answered. novox/hq ADR 0027.
This commit is contained in:
2026-08-31 17:12:46 +02:00
parent ab1dd34d12
commit ee84b624b1
8 changed files with 123 additions and 58 deletions
+20 -20
View File
@@ -27,13 +27,13 @@ func onNetwork(nodes ...string) map[string][]Provider {
for _, n := range nodes {
out = append(out, Provider{Node: n, At: n + ".internal"})
}
return map[string][]Provider{"database": out}
return map[string][]Provider{"postgres-database": out}
}
func brokeredShelf() map[string]Manifest {
return shelf(
Manifest{Module: "postgres", Version: "1", Provides: FromAnywhere("database")},
Manifest{Module: "meshboard", Version: "1", Requires: []string{"database"}},
Manifest{Module: "postgres", Version: "1", Provides: FromAnywhere("postgres-database")},
Manifest{Module: "meshboard", Version: "1", Requires: []string{"postgres-database"}},
)
}
@@ -60,7 +60,7 @@ func TestWhatAMachineTakesFromElsewhereIsRecorded(t *testing.T) {
if len(got.Needs) != 1 {
t.Fatalf("got %v", got.Needs)
}
if got.Needs[0].Name != "database" || got.Needs[0].From != "anchor" {
if got.Needs[0].Name != "postgres-database" || got.Needs[0].From != "anchor" {
t.Fatalf("got %v", got.Needs[0])
}
if got.Needs[0].For != "meshboard" {
@@ -99,7 +99,7 @@ func TestSayingWhichOneSettlesIt(t *testing.T) {
got, err := Resolve(brokeredShelf(), []string{"meshboard"}, reachable(),
World{
Offered: onNetwork("anchor", "archive"),
Pinned: map[string]string{"database": "archive"},
Pinned: map[string]string{"postgres-database": "archive"},
})
if err != nil {
t.Fatal(err)
@@ -115,7 +115,7 @@ func TestBeingPointedAtAMachineThatDoesNotProvideItIsRefused(t *testing.T) {
_, err := Resolve(brokeredShelf(), []string{"meshboard"}, reachable(),
World{
Offered: onNetwork("anchor", "archive"),
Pinned: map[string]string{"database": "somewhere-else"},
Pinned: map[string]string{"postgres-database": "somewhere-else"},
})
if err == nil {
t.Fatal("a machine was silently given a different database from the one chosen")
@@ -131,7 +131,7 @@ func TestOneProviderDoesNotOverruleAChoice(t *testing.T) {
_, err := Resolve(brokeredShelf(), []string{"meshboard"}, reachable(),
World{
Offered: onNetwork("anchor"),
Pinned: map[string]string{"database": "archive"},
Pinned: map[string]string{"postgres-database": "archive"},
})
if err == nil {
t.Fatal("the only database was used although another was chosen")
@@ -145,9 +145,9 @@ func TestACatalogueThatDisagreesAboutScopeIsRefused(t *testing.T) {
// If one module says a database is local and another says it is anywhere, the same
// requirement means two things depending on which one happens to answer it.
_, err := Resolve(shelf(
Manifest{Module: "postgres", Version: "1", Provides: FromAnywhere("database")},
Manifest{Module: "sqlite", Version: "1", Provides: Offers("database")},
Manifest{Module: "meshboard", Version: "1", Requires: []string{"database"}},
Manifest{Module: "postgres", Version: "1", Provides: FromAnywhere("postgres-database")},
Manifest{Module: "sqlite", Version: "1", Provides: Offers("postgres-database")},
Manifest{Module: "meshboard", Version: "1", Requires: []string{"postgres-database"}},
), []string{"meshboard"}, workstation(), World{})
if err == nil {
t.Fatal("a catalogue that disagrees about where a database lives was accepted")
@@ -200,10 +200,10 @@ func TestASiteScopedProvisionIsRefused(t *testing.T) {
func boundShelf() map[string]Manifest {
return shelf(
Manifest{Module: "postgres", Version: "1", Provides: FromAnywhere("database"),
Serves: map[string]map[string]any{"database": {"port": 5432, "driver": "postgres"}}},
Manifest{Module: "meshboard", Version: "1", Requires: []string{"database"},
Binds: map[string]string{"database": "/etc/meshboard/database.json"}},
Manifest{Module: "postgres", Version: "1", Provides: FromAnywhere("postgres-database"),
Serves: map[string]map[string]any{"postgres-database": {"port": 5432, "driver": "postgres"}}},
Manifest{Module: "meshboard", Version: "1", Requires: []string{"postgres-database"},
Binds: map[string]string{"postgres-database": "/etc/meshboard/database.json"}},
)
}
@@ -227,7 +227,7 @@ func TestAnAppIsToldWhereItsDatabaseIs(t *testing.T) {
// Knowing it needs the anchor's database is useless to the program that needs it unless the
// program is told. This is the whole point of the field.
got, err := Resolve(boundShelf(), []string{"meshboard"}, reachable(),
World{Offered: map[string][]Provider{"database": {{Node: "anchor", At: "anchor.internal",
World{Offered: map[string][]Provider{"postgres-database": {{Node: "anchor", At: "anchor.internal",
Serves: map[string]any{"port": 5432, "driver": "postgres"}}}}})
if err != nil {
t.Fatal(err)
@@ -246,7 +246,7 @@ func TestItSaysItCarriesNoCredential(t *testing.T) {
// A missing field looks like a bug; a stated absence looks like a boundary. Somebody wiring
// this up must not spend an afternoon looking for the password field.
got, _ := Resolve(boundShelf(), []string{"meshboard"}, reachable(),
World{Offered: map[string][]Provider{"database": {{Node: "anchor", At: "anchor.internal"}}}})
World{Offered: map[string][]Provider{"postgres-database": {{Node: "anchor", At: "anchor.internal"}}}})
told := binding(t, mustDeclare(t, got))
note, _ := told["generated"].(string)
if !strings.Contains(note, "no credential") {
@@ -264,7 +264,7 @@ func TestTwoMachinesThatCannotReachEachOtherAreRefused(t *testing.T) {
// that reports itself configured and does not work. Said here rather than discovered as a
// connection timing out.
_, err := Resolve(boundShelf(), []string{"meshboard"}, workstation(), // not on the network
World{Offered: map[string][]Provider{"database": {{Node: "anchor", At: "anchor.internal"}}}})
World{Offered: map[string][]Provider{"postgres-database": {{Node: "anchor", At: "anchor.internal"}}}})
if err == nil {
t.Fatal("an app was pointed at a database it has no path to")
}
@@ -279,7 +279,7 @@ func TestTwoMachinesThatCannotReachEachOtherAreRefused(t *testing.T) {
func TestTheProviderBeingOffTheNetworkIsAlsoRefused(t *testing.T) {
// Both directions, because the failure is identical from either end and the remedy differs.
_, err := Resolve(boundShelf(), []string{"meshboard"}, reachable(),
World{Offered: map[string][]Provider{"database": {{Node: "anchor"}}}})
World{Offered: map[string][]Provider{"postgres-database": {{Node: "anchor"}}}})
if err == nil {
t.Fatal("an app was pointed at a database that is not on the private network")
}
@@ -307,7 +307,7 @@ func TestBindingSomethingAnsweredHereWritesNothing(t *testing.T) {
func TestBindingWhatYouDoNotRequireIsRefused(t *testing.T) {
_, err := ParseManifest([]byte(`{"module":"app","version":"1",
"binds":{"database":"/etc/app/db.json"}}`))
"binds":{"postgres-database":"/etc/app/db.json"}}`))
if err == nil {
t.Fatal("a module was told about something it never asked for")
}
@@ -318,7 +318,7 @@ func TestBindingWhatYouDoNotRequireIsRefused(t *testing.T) {
func TestServingWhatYouDoNotProvideIsRefused(t *testing.T) {
_, err := ParseManifest([]byte(`{"module":"app","version":"1",
"serves":{"database":{"port":5432}}}`))
"serves":{"postgres-database":{"port":5432}}}`))
if err == nil {
t.Fatal("a module served something it does not provide")
}