Rulings of 2026-10-04
Rulings of 2026-10-04
The decision records are authoritative. This page is the dated log of rulings they quote, kept verbatim, corrections included.
The operator’s answers to the eight open design questions in
research synthesis section 19, and to the Elysia question (section 11).
These are decisions, not proposals. The implementation plan follows them.
| # | Question | Ruling |
|---|---|---|
| 1 | Measure the agent hypothesis before building? | No. Mesh is built regardless. The measurement is not a gate. |
| 2 | How much logic is generated per resource? | As much as Ash puts in its resources, or more. Generated code carries the behaviour; the shared engine stays thin. |
| 3 | Atomic and bulk writes in v1 | Atomic single-record updates (changes folded into the statement) plus bulk actions with the per-record stream strategy. Batched-atomic comes later. |
| 4 | Mandatory data-layer capabilities | Select, insert, update, delete, transactions, filters, sort, pagination. Joins, aggregates, upserts and atomic expressions are declared capabilities; using one an adapter lacks is a build-time error, never a silent in-memory fallback. |
| 5 | May extensions contribute to each other’s part of the model? | Only through contribution points the owning extension publishes and the contributor declares in its manifest. Anything else is a build error. |
| 6 | Policy engine depth | Simple tier first: ordered allow/deny checks, read policies as query filters, structured breakdown output. Keep the policy formula representation so a SAT solver can be added later. |
| 7 | Durable workflows | Compare durable engines now, with the goal of defining Mesh’s workflow adapter interface. The in-process runner is the first adapter. |
| 8 | First server adapter | Neither Elysia nor Hono first. Mesh is not to be tied to web apps, or to any kind of application: like Ash, it must serve a CLI, a daemon, a web app or an API equally. The operator’s words: “let’s test Mesh with a leaner thing that will require less wiring.” This is a statement about how to test first, not a ruling that a CLI is the first transport. (Corrected 2026-10-04; the earlier text said “The first transport is a CLI”, which was the lead’s misreading.) |
Elysia
Agreed: Elysia is not core. The operator’s earlier weight on Elysia should not shape the
transport contract. Elysia stays a candidate HTTP adapter once the generic contract exists.
Consequences for the proposal (synthesis Step 3)
- Section 15 “Server and API protocol” adapter: no transport is chosen as first. The core’s
interface is an in-process function call; every transport is an optional adapter over it. - Section 17 phase 1 “Enter”: every transport, the CLI included, obtains the caller’s scope
through the actor-resolver adapter contract. Mesh core defines no flags, no tenant and no
login; tenant belongs to the multitenancy extension. (Corrected 2026-10-04: an earlier line
here made the CLI define actor/tenant/context, which pulled app concerns into core.) - A new research document (durable engines, adapter-interface focus) feeds the jobs and
workflows adapter contract.
Lead decisions (operator may overrule)
- Composed contracts module. Mesh generates one self-contained
mx.contractsmodule from
core plus the enabled extensions, so extensions add tags without any MX change. Follows
ruling 5 (contributions only through declared points: a closedresource.childrenmust
accept children an extension contributes). Stated to the MX lead in
Mesh’s answers to MX onmx.contracts, 2026-10-04; no decision-142 addendum needed.
Implementation-plan rulings (2026-10-04)
| Q | Ruling |
|---|---|
| Q1/Q13 | v1 = M0–M14, CLI only, SQLite and Postgres. HTTP adapter (M15) after v1. |
| Q3 | Rely on established tools wherever possible (operator’s standing position). SQL adapters use Drizzle for queries and drizzle-kit for migrations, behind Mesh’s data-layer contract. Mesh still compiles its own expression tree into Drizzle’s SQL builder. |
| Q4 | Withdrawn: it brought app concerns into core. The CLI transport resolves scope via the actor-resolver adapter; tenant is the multitenancy extension’s. |
| Q8 | Build and test locally; no CI until MX packages are published. |
| Q2, Q5–Q7, Q9–Q12, Q14 | Lead decided: take the plan’s recommended option for each (plan section 9). |
Review note (2026-10-04, later)
The operator asked for a review of every decision above. Until that review is closed, read the
tables with these corrections:
- “Plan ruling Q4” was never an operator ruling. The operator said only that app-specific
concerns must not enter Mesh’s architecture. The actor-resolver adapter, “scope = actor and
context” and “tenant belongs to the multitenancy extension” were the lead’s inventions. - “Plan ruling Q3” records the operator’s position (“the more we can rely on well-established
tools the better”); choosing Drizzle and drizzle-kit specifically was the lead’s application
of it. - Q2, Q5–Q7, Q9–Q12 and Q14 were accepted by the lead in one line without analysis. They are
provisional. - “CLI only” in Q1/Q13 follows the misreading of ruling 8 and is void; “M0–M14, SQLite and
Postgres, HTTP after” is what the operator chose.
Rulings after the decision review (2026-10-04, operator)
| Topic | Ruling |
|---|---|
| Expressions | One expression tree, evaluated both in memory and in SQL (as Ash does). Replaces the plan’s “translatable expressions only ever run as SQL” (plan Q10/N2). |
| v1 line | v1 = M0–M8 plus M10: workspace, build skeleton, run skeleton, data-layer contract, expressions, action lifecycle, extension host, relationships/calculations/aggregates, policies, migrations and Postgres. |
| After v1 | M9 (bulk, identities, upserts; overrides the bulk half of ruling 3), M11 and M12 (outbox, jobs, workflows; replaces ruling 7’s “in-process runner first”; the adapter interface stays a design document), M13 (agent and test surface), M14 (Node parity, single binary), M15 (HTTP). |
| CI | None until the MX lead says the @mxlang packages are published. The operator handles publishing with the MX lead. |
| Architecture process | The final architecture is designed following the engineering:architecture skill (decision records). |
| Docs site | apps/docs in the repo, built with docmd (docmd.io). Two top-level sections: Docs (for users) and Architecture (for contributors: roadmap, every decision, overviews, in-depth pages, research results). Rule for Architecture: document everything that cannot be understood by looking at a single code file. |
| Runtime | Node is dropped. Mesh runs on Bun only (old M14 disappears). The run-time library keeps to web-standard APIs where it can. |
| MCP | Not built. The operator prefers CLIs made for agents (fewer tokens). Agent surface: the generated rules file, later a CLI adapter generated from the action list. |
| Research | The research documents move into the docs site under Architecture / Research. The repo docs become the source of truth; notes/ stops being it. |
| Docs deployment | The docs site is deployed with Coolify on netcup at mesh.saulo.tech. |
| Order of work | Framework code (M0 onward) starts once the roadmap and decision records are published; nothing else gates it. |
| Licence and visibility | Mesh is fully open source under the MIT licence. Nothing in the docs site is private. |
| Vocabulary | Copy Ash’s DSL for now (names and structure). After v1, review it and optimise for what feels natural in MX. Resource files and every example always use MX concise syntax. |
| User docs as live spec | Pages under Docs are written before the implementation, and sometimes before the architecture, to model the intended developer experience and expose problems the architecture pages hide. Replaces the earlier practice “Docs describe only what exists today”. Every Docs page opens with a warning that it is a live spec of how things will be and that Mesh is not released. First set: installation, usage, project structure, a todo-list example. |
| MX | MX is not replaceable: it is core, not an adapter. No “front end” adapter slot and no frontend-mx package; the tag contracts live in the core compiler package. |
| Repository shape | A bun workspace monorepo (packages/, apps/, examples/*), started 2026-10-04 as roadmap milestone M0. |
Trailing ? in attribute names |
Not enabled, although the MX lead confirmed the data target could allow it. In TypeScript name? means optional, so allow-nil? reads wrong; it would permanently block a future name?=expr syntax; it diverges from Marko’s translator; and a bare boolean attribute already carries the predicate meaning. Spelling stays: Ash names in kebab-case with ? dropped. The same holds for tag names: Mesh declares no tag ending in ? (MX still allows it, as Marko does). |
Implementation note, 2026-10-04: the first live-spec set grew to seven new pages. Calling actions, Configuration and Command-line tool supplement the four named in the ruling to make their examples complete. The ruling above is preserved verbatim.
Lead decisions of the architecture-docs brief (2026-10-04)
Decided by the lead; the operator may overrule. Quoted from the brief the lead gave for the roadmap and the decision records.
- Scope is a plain argument. The caller passes
{ actor, context }on every action call, as Ash’sactor:option. Drop the actor-resolver contract, theactor-devpackage, the action registry and the transport contract from v1. N4 is moot. - Tenant: open. In Ash, tenancy is in core. Nobody ruled where it lives in Mesh and multitenancy is not scheduled. Write it as a Proposed ADR with options; drop the “scope contribution point” from the extension host.
- Walking skeleton ends in a function call: a test and a ~20-line script in
examples/blogcall the generated handlers against SQLite. Notransport-cli, no exit codes, no--stdin, noworkercommand. publicand default-deny before policies (old D10, D6): no transport exists in v1, sopublichas nothing to filter yet, and theauthorization: "none"flag is wiring for nothing. Drop both from M2; deny-by-default arrives with the policies extension. Record whatpublicwill mean as a Proposed ADR.- Outbox relay and rule R3 are deferred with the workflow milestones. durable engines stays the design input for a future workflow/job adapter contract; a small spike “DBOS worker on Bun” precedes any engine choice. No engine is a clear winner (DBOS best fit on paper for workflows, pg-boss for plain jobs on Postgres).
- Validations are classified like changes now that an in-memory evaluator exists: a translatable validation folds into the atomic statement; rework the atomic-by-default rule and the
publishexample accordingly. - N1 Zod behind Standard Schema: accepted. N3 OpenTelemetry API direct: accepted. N2 (in-memory data adapter vs SQLite
:memory:): reconsider now that the in-memory evaluator exists; decide, with reasons, in an ADR. - The vocabulary on
mainis provisional. The 26 tag contracts were copied from an MX test fixture; several rules were inferred by the dev or ruled by the lead during code review (PR #1 report, “Inferred by me”; rounds 1–4). Write a Proposed ADR plus a “Vocabulary design” page listing every open vocabulary question (inferred rules, review rulings, and the new tags each v1 milestone adds) so the operator can rule on them in one pass before M1 builds a model on them.
Later the same day
Further decisions by the lead on 2026-10-04, given while the roadmap and the decision records were written. The operator may overrule each.
publicattributes.publicis recorded in the model, as Ash recordspublic?, and nothing in v1 reads it. It is not a not-implemented build error.- Atomic updates in v1. “In v1 a validation or change that reads the stored record makes the action non-atomic, and the action must say
require_atomic?false, as in Ash. Folding record-reading validations into the statement, with the failure protocol you designed, becomes a Proposed ADR for after v1.” This replaces the brief’s “a translatable validation folds into the atomic statement”. Translatable validations that need no stored record still run before the statement on either path; the in-memory evaluator runs validations on the non-atomic path. - Write policies on atomic actions. A record-reading write policy on an atomic action folds into the statement as a filter; a forbidden row reports not found. Accepted first as Ash’s behaviour; the research shows Ash compiles the check as an expression that raises and reports forbidden, so the lead kept not-found as a deliberate deviation and a working assumption, and made the point a Proposed record for the operator to rule.
has-one. An implicit unique index for v1, recorded as a Proposed deviation from Ash, with the alternative “a build error unless the foreign key is declared unique” once identities exist.- Spelling of names. The MX maintainers measured on MX
main(7a404916) that_is accepted in tag and attribute names and that a trailing?in an attribute name is not accepted and never will be (Marko’s syntax rule: letters, digits and._:-). “Mesh names are Ash’s names in kebab-case with?dropped:belongs_to→belongs-to,allow_nil?→allow-nil,require_atomic?→require-atomic. The mapping is mechanical and one-to-one, it matches what is on main, and it avoids renaming twice.” - Adapter-contributed commands.
mesh db pushandmesh migrateare contributed by the SQL adapters. The rule that MX is imported only by packages that declare tag contracts is checked byverifyfrom M1. - Expression semantics. The record stays Proposed and must be ruled before M4.
- Deciders on public pages are named by role only: operator, lead, roadmap author.
- In-depth pages for policies and for relationships, calculations and aggregates are written in the milestones that build them, not before: the rule is to document what cannot be understood from one code file, and that code does not exist yet.
- Published history. The rulings log is published verbatim, corrections included, with a banner saying the decision records are authoritative. Plan revision 2 is published as a superseded page, excluded from search and from
llms.txt.