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
+32 -6
View File
@@ -26,13 +26,28 @@ type Toolchain struct {
Base string
// Artifact is which of that module's artifacts is the compiling one.
Artifact string
// Compile is what runs inside it, relative to the module's own directory. The output goes to
// Output, which is what gets packed.
// Compile is what runs inside it, relative to the module's own directory.
//
// The output directory is appended by the builder, per artifact, because one module may
// declare several bundles — a daemon in one language, tools in another, a package in a third —
// and a toolchain with one fixed output would have them overwrite each other and then be
// packed together.
Compile []string
// Output is the directory the compiled result lands in, relative to the module's directory.
Output string
// OutputFlag is how this compiler is told where to put its output.
OutputFlag string
}
// Out is where one artifact's compiled output lands, inside the module's own directory.
//
// **Per artifact, never per toolchain.** A module is one piece of software and may still be
// written in several languages — a daemon in one, a tool in another, a package in a third (ADR
// 0040). Each bundle is compiled and packed alone, so what a machine unpacks is that artifact and
// nothing else.
//
// Under a directory named for the build rather than beside the source, so a pack never sweeps up
// the module's own working files, and two builds of one commit see the same tree.
func Out(artifact string) string { return ".mesh-build/" + artifact }
// toolchains is every language the mesh can build.
//
// **A closed list, and adding to it is a decision rather than a configuration.** Every language is
@@ -53,9 +68,20 @@ var toolchains = []Toolchain{
Compile: []string{
"node", "/app/node_modules/typescript/bin/tsc",
"--module", "NodeNext", "--moduleResolution", "NodeNext",
"--target", "ES2022", "--outDir", "dist",
"--target", "ES2022",
},
Output: "dist",
OutputFlag: "--outDir",
},
{
Language: "python",
Base: "mesh-tools-python",
Artifact: "build",
// Nothing to compile: what a bundle needs is the module's own code and its dependencies
// resolved, so the "compile" is an install into the output directory. Named here rather
// than left implicit because a reader comparing two toolchains should be able to see what
// each actually does.
Compile: []string{"python", "-m", "pip", "install", "--no-compile", "--target"},
OutputFlag: "",
},
}