This moves the last three modules whose own code ran in runtime-image containers. They follow the pattern of waves 1–3 (#245, #248): one commit per module; the container, Dockerfile, build bases and bus credential go; a code bundle with loads and env; words, ports included, are set directly in env.
Depends on mesh-controller #255 (the builder installs a module's own npm packages). Without it these bundles fail to compile.
mesh-catalog: pg comes from its package.json, inlined into the bundle. prepares: true needs a container running the module's own artifact, so it becomes a run-once process: node prepare/index.js, with DATABASE_URL_FILE and no bus, and restart-on: database-url. mesh-state and the broker secret are gone.
mongodb: the client now uses the official mongodb driver instead of mongosh (ADR 0198 §4). Tool output is unchanged (relaxed EJSON). It reaches the server at 127.0.0.1:${port:27017}. secrets-owner: 999:999 is dropped: the module's own root.secret goes to the runtime's account, and the mongo server gets its own 0400 copy owned by 999, server-root.secret, rendered from ${secret:root}.
mssql: the client now uses the mssql (tedious) driver instead of sqlcmd. There is one session per call, rows still come back via FOR JSON, and the consumer's password in holdsLogin is a bound parameter. It reaches the server at 127.0.0.1:${port:1433}. Caller statements still run only as the reader login (issue 193). The one-line rule and -x are gone, because sqlcmd's :!! commands and $(VAR) substitution no longer exist. The reader test now drives a fake session instead of a fake sqlcmd, and adds a test for the bound password.
Proven
Each bundle was built the way the builder will build it: own dependencies installed, then tsc, then esbuild into one file per entrypoint, with no node_modules in the output. Each was launched over MCP stdio from a directory with no node_modules:
mesh-catalog: prepare migrated a real postgres and exited 0. tools/list answered with 5 tools, catalog_modules was called successfully, and index subscribed to both of its events.
mongodb: mongodb_list_databases and mongodb_query answered against real mongo 7. The provisioner created a dbOwner user that can authenticate. canAuthenticateAs returned true for the right password and false for a wrong one, and drop is idempotent.
mssql: mssql_list_databases answered, and mssql_query answered as the reader against SQL Server 2022. The provisioner created the login and database. holdsLogin returned true for the right password and false for a wrong one, and drop is idempotent.
Strict tsc -p type-check passes for all three; mssql's npm test passes 4 of 4.
mesh-controller go test ./... passes with this branch as the sibling catalogue, apart from the known resolver test. A throwaway declaration test (deleted afterwards) confirmed that none of the three runs a container with its own code and that every word is filled. The runtime gets words such as mongodb://root@127.0.0.1:27117/… and mssql://sa@127.0.0.1:1533/master, and the secret files those words name are owned by the operator account.
Still needs live proof / known gap
A failed run-once process does not gate its module's code in the shared node runtime. mesh-host gates only run-once containers and actions, and the runtime is another module. So mesh-catalog's prepare runs before the runtime on apply, but its failure would not stop the catalogue's handlers from serving. ADR 0198 §3 implies a gate; that is a host/controller follow-up.
node must be on the machine for the run-once process, as it already is for route-adapter.
Live: the provisioners and tools of all three answer from node-tools, docker ps shows no mesh-catalog, mesh-mongodb or mesh-mssql container, and the mongo server restarts cleanly with server-root.secret.
This moves the last three modules whose own code ran in runtime-image containers. They follow the pattern of waves 1–3 (#245, #248): one commit per module; the container, Dockerfile, build bases and bus credential go; a `code` bundle with `loads` and `env`; words, ports included, are set directly in `env`.
**Depends on mesh-controller #255** (the builder installs a module's own npm packages). Without it these bundles fail to compile.
- **mesh-catalog**: `pg` comes from its package.json, inlined into the bundle. `prepares: true` needs a container running the module's own artifact, so it becomes a run-once process: `node prepare/index.js`, with `DATABASE_URL_FILE` and no bus, and `restart-on: database-url`. `mesh-state` and the broker secret are gone.
- **mongodb**: the client now uses the official `mongodb` driver instead of mongosh (ADR 0198 §4). Tool output is unchanged (relaxed EJSON). It reaches the server at `127.0.0.1:${port:27017}`. `secrets-owner: 999:999` is dropped: the module's own `root.secret` goes to the runtime's account, and the mongo server gets its own 0400 copy owned by 999, `server-root.secret`, rendered from `${secret:root}`.
- **mssql**: the client now uses the `mssql` (tedious) driver instead of sqlcmd. There is one session per call, rows still come back via `FOR JSON`, and the consumer's password in `holdsLogin` is a bound parameter. It reaches the server at `127.0.0.1:${port:1433}`. Caller statements still run only as the reader login (issue 193). The one-line rule and `-x` are gone, because sqlcmd's `:!!` commands and `$(VAR)` substitution no longer exist. The reader test now drives a fake session instead of a fake sqlcmd, and adds a test for the bound password.
**Proven**
- Each bundle was built the way the builder will build it: own dependencies installed, then tsc, then esbuild into one file per entrypoint, with no node_modules in the output. Each was launched over MCP stdio from a directory with no node_modules:
- mesh-catalog: prepare migrated a real postgres and exited 0. `tools/list` answered with 5 tools, `catalog_modules` was called successfully, and `index` subscribed to both of its events.
- mongodb: `mongodb_list_databases` and `mongodb_query` answered against real mongo 7. The provisioner created a dbOwner user that can authenticate. `canAuthenticateAs` returned true for the right password and false for a wrong one, and drop is idempotent.
- mssql: `mssql_list_databases` answered, and `mssql_query` answered as the reader against SQL Server 2022. The provisioner created the login and database. `holdsLogin` returned true for the right password and false for a wrong one, and drop is idempotent.
- Strict `tsc -p` type-check passes for all three; mssql's `npm test` passes 4 of 4.
- mesh-controller `go test ./...` passes with this branch as the sibling catalogue, apart from the known resolver test. A throwaway declaration test (deleted afterwards) confirmed that none of the three runs a container with its own code and that every word is filled. The runtime gets words such as `mongodb://root@127.0.0.1:27117/…` and `mssql://sa@127.0.0.1:1533/master`, and the secret files those words name are owned by the operator account.
**Still needs live proof / known gap**
- A failed run-once *process* does not gate its module's code in the shared node runtime. mesh-host gates only run-once containers and actions, and the runtime is another module. So mesh-catalog's prepare runs before the runtime on apply, but its failure would not stop the catalogue's handlers from serving. ADR 0198 §3 implies a gate; that is a host/controller follow-up.
- `node` must be on the machine for the run-once process, as it already is for route-adapter.
- Live: the provisioners and tools of all three answer from node-tools, `docker ps` shows no `mesh-catalog`, `mesh-mongodb` or `mesh-mssql` container, and the mongo server restarts cleanly with `server-root.secret`.
The mesh-catalog container goes with its Dockerfile, build bases, bus credential and mesh-state directory. Its words are the database URL file where the mesh writes it. `pg` is a dependency in its package.json, which the builder now installs and inlines into the bundle (mesh-controller: a TypeScript bundle installs its module's own packages). `prepares: true` needs a container running the module's own artifact, so it becomes what ADR 0198 §3 says it is: prepare/index.js run by node as a run-once process, with the same words and no bus, before the runtime is started with the version that needs it, and again when the database URL changes.
The mesh-mongodb container goes with its Dockerfile, build bases and bus credential. Its client shelled out to mongosh, which no machine's system carries, so it now speaks to the server through the official mongodb driver its package.json names, inlined into the bundle by the builder (ADR 0198 §4); the tools answer exactly as before (relaxed Extended JSON). The server is reached on loopback at the port the machine published (${port:27017}). The root secret was owned by the mongo image's user (secrets-owner 999:999), which the runtime's account cannot read; the module's own copy is now the runtime's, and the server is given its own 999-owned copy rendered from the same secret.
The mesh-mssql container goes with its Dockerfile (and the sqlcmd it fetched), build bases and bus credential. The client speaks TDS through the mssql driver its package.json names, inlined into the bundle by the builder (ADR 0198 §4): one session per call as one sqlcmd invocation was, FOR JSON rendering rows exactly as before, the consumer's password checked as a bound parameter. A caller's statement still runs only as the reader login (issue 193); the one-line rule and -x guarded against sqlcmd's own commands and variable substitution, which no longer stand between the caller and the server. The server is reached on loopback at the port the machine published (${port:1433}). The reader test drives a fake session in place of a fake sqlcmd.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
This moves the last three modules whose own code ran in runtime-image containers. They follow the pattern of waves 1–3 (#245, #248): one commit per module; the container, Dockerfile, build bases and bus credential go; a
codebundle withloadsandenv; words, ports included, are set directly inenv.Depends on mesh-controller #255 (the builder installs a module's own npm packages). Without it these bundles fail to compile.
pgcomes from its package.json, inlined into the bundle.prepares: trueneeds a container running the module's own artifact, so it becomes a run-once process:node prepare/index.js, withDATABASE_URL_FILEand no bus, andrestart-on: database-url.mesh-stateand the broker secret are gone.mongodbdriver instead of mongosh (ADR 0198 §4). Tool output is unchanged (relaxed EJSON). It reaches the server at127.0.0.1:${port:27017}.secrets-owner: 999:999is dropped: the module's ownroot.secretgoes to the runtime's account, and the mongo server gets its own 0400 copy owned by 999,server-root.secret, rendered from${secret:root}.mssql(tedious) driver instead of sqlcmd. There is one session per call, rows still come back viaFOR JSON, and the consumer's password inholdsLoginis a bound parameter. It reaches the server at127.0.0.1:${port:1433}. Caller statements still run only as the reader login (issue 193). The one-line rule and-xare gone, because sqlcmd's:!!commands and$(VAR)substitution no longer exist. The reader test now drives a fake session instead of a fake sqlcmd, and adds a test for the bound password.Proven
tools/listanswered with 5 tools,catalog_moduleswas called successfully, andindexsubscribed to both of its events.mongodb_list_databasesandmongodb_queryanswered against real mongo 7. The provisioner created a dbOwner user that can authenticate.canAuthenticateAsreturned true for the right password and false for a wrong one, and drop is idempotent.mssql_list_databasesanswered, andmssql_queryanswered as the reader against SQL Server 2022. The provisioner created the login and database.holdsLoginreturned true for the right password and false for a wrong one, and drop is idempotent.tsc -ptype-check passes for all three; mssql'snpm testpasses 4 of 4.go test ./...passes with this branch as the sibling catalogue, apart from the known resolver test. A throwaway declaration test (deleted afterwards) confirmed that none of the three runs a container with its own code and that every word is filled. The runtime gets words such asmongodb://root@127.0.0.1:27117/…andmssql://sa@127.0.0.1:1533/master, and the secret files those words name are owned by the operator account.Still needs live proof / known gap
nodemust be on the machine for the run-once process, as it already is for route-adapter.docker psshows nomesh-catalog,mesh-mongodbormesh-mssqlcontainer, and the mongo server restarts cleanly withserver-root.secret.The mesh-mongodb container goes with its Dockerfile, build bases and bus credential. Its client shelled out to mongosh, which no machine's system carries, so it now speaks to the server through the official mongodb driver its package.json names, inlined into the bundle by the builder (ADR 0198 §4); the tools answer exactly as before (relaxed Extended JSON). The server is reached on loopback at the port the machine published (${port:27017}). The root secret was owned by the mongo image's user (secrets-owner 999:999), which the runtime's account cannot read; the module's own copy is now the runtime's, and the server is given its own 999-owned copy rendered from the same secret.The mesh-mssql container goes with its Dockerfile (and the sqlcmd it fetched), build bases and bus credential. The client speaks TDS through the mssql driver its package.json names, inlined into the bundle by the builder (ADR 0198 §4): one session per call as one sqlcmd invocation was, FOR JSON rendering rows exactly as before, the consumer's password checked as a bound parameter. A caller's statement still runs only as the reader login (issue 193); the one-line rule and -x guarded against sqlcmd's own commands and variable substitution, which no longer stand between the caller and the server. The server is reached on loopback at the port the machine published (${port:1433}). The reader test drives a fake session in place of a fake sqlcmd.