One module, several languages, each bundle packed alone

A module is one piece of software and may still carry a daemon in one language,
tools in another and a package in a third. The first cut compiled every bundle
into the toolchain's single output directory, so two of them would have
overwritten each other and then been packed together — one artifact containing
both, published twice.

So output is a property of the artifact, not of the toolchain, and the toolchain
says how it is told where to write rather than where it writes. Under a directory
named for the build rather than beside the source, so a pack never sweeps up the
module's own working files.

A second toolchain is declared so the multi-language path is exercised rather
than asserted — a list with one entry cannot fail the way a list with four will.

And the fake compiler in the tests now writes where it was TOLD to. One that
always wrote to a fixed place would have passed whether or not each artifact got
its own directory, which is the whole of what these tests are for.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
2026-09-15 02:09:06 +02:00
parent 4b7bd1b3e2
commit e3748bc06f
4 changed files with 155 additions and 22 deletions
+35 -2
View File
@@ -14,8 +14,8 @@ func TestADeclaredLanguageSelectsItsToolchain(t *testing.T) {
if chain.Base == "" || chain.Artifact == "" {
t.Fatalf("a toolchain names no base to compile in: %+v", chain)
}
if len(chain.Compile) == 0 || chain.Output == "" {
t.Fatalf("a toolchain says nothing about how to compile or where output lands: %+v", chain)
if len(chain.Compile) == 0 {
t.Fatalf("a toolchain says nothing about how to compile: %+v", chain)
}
}
@@ -54,3 +54,36 @@ func TestABundleMustSayWhatItIsWrittenIn(t *testing.T) {
t.Fatalf("the refusal does not say a language is required: %v", err)
}
}
// **One module, several languages, and each bundle packed alone.**
//
// A module is one piece of software (ADR 0040) and may still carry a daemon in one language, tools
// in another and a package in a third. Compiling them into one output directory would have them
// overwrite each other and then be packed together, so output is a property of the artifact rather
// than of the toolchain.
func TestTwoBundlesInOneModuleDoNotShareAnOutputDirectory(t *testing.T) {
first, second := Out("daemon"), Out("tools")
if first == second {
t.Fatalf("two artifacts compile into the same place (%q), so one would overwrite the "+
"other and both would be packed together", first)
}
for _, out := range []string{first, second} {
if strings.HasPrefix(out, "/") || strings.Contains(out, "..") {
t.Fatalf("%q leaves the module's own directory", out)
}
}
}
// And the mesh can say what it builds, which is what a refusal quotes.
func TestTheMeshSaysWhichLanguagesItBuilds(t *testing.T) {
spoken := Languages()
if len(spoken) < 2 {
t.Fatalf("only %v — this test exists to keep the multi-language path real rather than "+
"theoretical", spoken)
}
for _, language := range spoken {
if _, err := ToolchainFor(language); err != nil {
t.Fatalf("%q is listed as buildable and has no toolchain: %v", language, err)
}
}
}