Naming grammar
Node, area, unit, backend and role segments use closed word lists wherever an ambiguous name would spread.
- System owned namespace
- Layer core • lib • app • host
- Role schema • runtime • test
- Operation specific function
2027 · MerTek technology
Engineering reference / System overview
Names and layers that show who owns code
MTK names every file, folder and declaration for the system and layer that owns it. Dependencies point one way: core mechanisms, then Trident libraries, then applications, then products. A lower layer never depends on application policy, and the build refuses an include or a reach that points the wrong way.
Worked example
The Reno warehouse runs one server and 60 handheld scanners on its palletyard app. Supervisors attach hold notes to damaged pallets, and those notes must never reach a scanner. A new developer is adding the notes and also needs a check-digit test for pallet labels.
Place each piece with the tier test. Apply the questions in order and stop at the first yes. The check-digit math is a generic mechanism any app could need, so it belongs in core. The rule "refuse bad labels at dock 4" is this warehouse's policy and stays in the app.
# Ask in order; the first yes decides the tier.
# core a generic mechanism any app could need, with no scenario
# value, choice or policy baked in -> C and t.* libraries
# kit a reusable authoring capability several
# interfaces compose, with no branding -> first-party .tri
# app users, scenes, schema, handlers, data
# and declared policy -> config plus .tri
# product skin, arrangement, storefront, pricing -> config plus .tri,
# its own repositoryLay the app out by convention. a/ is code both builds share, s/ is the server, and c/ is the scanner client. A leading _ marks a folder the runtime reads, and an unknown one refuses instead of being ignored.
palletyard/
a/ shared: compiled into every build
audience.tri the audience flagset every unit reads
labels.tri label rules both sides run
_security/ access policy vocabulary every build knows
_test/ tests beside the code they prove
s/ the server build only
main.tri
holds.tri receives hold requests
_auth/ the sign-in realm; a client build refuses it
_security/ private access implementations
c/ the scanner build only
main.tri
scan.tri
_db/
troves/holdNote.tri the store is the server's
_app/ _grant/ _host/ _target/Put shared vocabulary in a/ and protected data behind an audience. A declaration's locality is the root of its unit. The hold-note trove crosses only to connections granted supervisor or admin, so a scanner is never pushed a note row.
# a/audience.tri: the one declaration every audience row names.
flagset audience { scanner = 1, supervisor = 2, admin = 4 }
# _db/troves/holdNote.tri: pushed only at a supervisor or admin grant.
trove holdNote {
audience = supervisor | admin
u64 pallet = 0
text body = ""
}Cross from client to server only with send. The scanner asks the server to place a hold, and the server decides. A plain dotted reach from c/ into s/ refuses at compile, and so does a send to a handle the server never declared.
# c/scan.tri: a scanner asks; it never writes the note itself.
void askHold(u64 pallet, text reason) {
send s.holds.place(pallet, reason)
}
# s.holds.place(pallet, reason) without send refuses at compile.
# s/holds.tri: only a supervisor connection may place a hold.
handle place(const ctx, u64 pallet, text reason) require (ctx.audience.has(audience.supervisor), "supervisor audience") {
holdNote.insert({ pallet = pallet, body = reason })
}The C underneath follows the same direction. A node includes only the public headers of strictly lower nodes. The math library can use the type registry but never the database engine. An include that points up stops the build.
/* A Keel source: Keel is a tier-2 node. */
#include "keel/keel_time_civil.h" /* its own area's contract */
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "mertektypes/mertektypes.h" /* tier 0: strictly lower */
/* #include "merdb/merdb.h" refused: MerDB is tier 4, above Keel */The hold notes shipped with no scanner build able to name them, and a test read of a note from c/ stopped at compile. The check-digit math went to the platform team as a generic library member, and the dock-4 rule stayed in the app. Each later reviewer could tell where a change lived, and who owned it, from its path alone.
System diagram
Higher layers may use lower mechanisms. Lower layers do not know a particular application or product.
Inside the system
Follow the data, decisions, and access boundaries. Each diagram explains a concept used by applications.
Node, area, unit, backend and role segments use closed word lists wherever an ambiguous name would spread.
Each platform system has one primary home and one accountable boundary.
The layer graph rejects a lower layer that reaches into application or product policy.
A file may sit only where its node, its layer and its application root agree.
Key parts
These are the main boundaries, inputs, outputs, and failure rules. The examples show a specific use of each part.
A C file is named <node>_<area>[_<unit>][_<backend>][_<role>].c, and its node must match its folder. An app module's name is its path, so a/geometry/units.tri is a.geometry.units. A misplaced file is a build failure, never a style note.
A Windows-only clock source is named platform_clock_win32, so a reader knows its node, area and backend before opening it.
Core mechanisms sit below Trident libraries, which sit below applications and products. An edge may point only at a strictly lower tier, and siblings never include each other. Application policy never moves down into a mechanism.
The renderer includes no language runtime, so a host can draw a scene with no Trident at all, while Trident includes the renderer.
Each node declares its headers, areas and allowed includes, and the build checks the tree against those declarations. In an app, every leading-_ folder is a registered row, and a name the registry lacks refuses.
A misspelled _asets/ folder stops the build with a named refusal instead of silently importing nothing.
Code
Each example is short and complete enough to read on its own. Hover a dotted word for its definition.
Segments are lowercase and joined by single underscores. A backend token makes the whole file exclusive to that backend, and a role token puts it in its role's directory.
<node>_<area>[_<unit>...][_<backend>][_<role>].<ext>
platform_clock.h the clock area's public contract
platform_clock_posix.c the same area, every POSIX host
platform_clock_win32.c the same area, Windows only
merwire_canary.c the node's canary; it lives under test/
# backends: win32 posix linux darwin wasm
# roles: canary fixture harness bench fuzz oracle
An edge is legal only when it points at a strictly lower tier. Same-tier siblings never include each other, and a few pairs are forbidden outright.
T9 tools, apps
T8 host composition roots
T6 trident (includes thalassa)
T5 mermount, thalassa
T4 merdb, merjob, mermedia, nautilus
T3 store seams
T2 merwire, keel, draft
T1 mercrypto, chest, mercodec
T0 mertektypes, merprim, platform (include no node)
forbidden both ways: trident <-> merdb, nautilus <-> merdb
forbidden one way: thalassa -> trident, merdb -> trident
a, s, c and t name program roots and the library catalog, so a binding spelled as one refuses. A reader never wonders whether s means a local or the server.
flagset audience { scanner = 1, supervisor = 2, admin = 4 }
text main(text[] argv) {
audience s = audience.supervisor | audience.admin
return text(s.count())
}
# picker.tri:4:14: refused [L.ident] reserved root is not a name: found `s` naming a binding
A leading _ says a folder is about its directory; a trailing _ excludes a file or folder with everything below it. Every compile prints one line for each excluded name, so nothing drops out in silence.
palletyard/
a/
main.tri
labels.tri
printLabels_.tri excluded: one line in every compile names it
reports_/ excluded with its whole subtree
_db_/ a system folder, switched off
# a/main_.tri refuses: the entry is never excluded
The root a folder sits under decides which builds compile it. Endpoints are admitted under s/ alone, because a client build declares none.
a/_views/orderSummary.tri every build
a/_test/labels.tri every build's tests; never shipped
s/_endpoints/holds/list.tri the server only: an HTTP endpoint
s/_jobs/nightly.tri a job on the server's queue
c/_jobs/prefetch.tri a job on the scanner's own session
c/_db/troves/settings.tri a scanner-local store, never pushed
Uses
Review questions
Which data each client build may ever hold
Which capabilities are generic enough for the platform core
Which team owns each node and each application root