Furth FortuneEngineering reference
TECHNICAL DOCUMENTATION

2027 · MerTek technology

On this page

2027 / Application platform

MTK

MTK is MerTek's application platform: a C runtime, the Trident language, and shared systems for data, rendering, assets, compute and host access. An application is a folder of Trident source and configuration documents, and a host runs it under a grant it builds at launch. The same folder runs as a one-call check, a windowed session or a headless service.

Worked example

A tool-crib app for the Tulsa depot, from template to tested

The Tulsa depot's tool crib lends 1,800 calibrated tools to 2nd-shift mechanics. A loan is due back 12 hours after checkout. The crib computer needs no network access, and the app must refuse to start without its loan settings.

  1. Start from the template. tricli --new toolcrib --set id=tulsa.toolcrib writes the folder, with a/main.tri as the entry and _app/app.draft holding the identity every launch reports.

    # _app/app.draft
    text id = "tulsa.toolcrib"
    text name = "toolcrib"
    u32 major = 1
  2. Put the loan period in a settings document. Every line states its type, so 12h is checked as a duration when the deployment compiles. Changing the period later moves the deployment digest and leaves the program digest alone.

    # _app/config/crib.draft
    # Loan rules for the 2nd-shift tool crib
    duration loanPeriod = 12h
  3. Write the record and the rule. loanRequest is an outline: the fields a value must carry, each with a type and a default. dueAt adds a duration to an instant and returns an instant in the same time domain.

    # a/loans/rules.tri
    outline loanRequest {
        text tool = ""
        text badge = ""
        timepoint<unix> takenAt = 0
    }
    
    timepoint<unix> dueAt(loanRequest request, duration period) {
        timepoint<unix> taken = request.takenAt
        return taken + period
    }
    
    bool overdue(timepoint<unix> due, timepoint<unix> now) {
        return now > due
    }
  4. Read the settings and run the rule. main takes the tool and the badge from the command line and checks the settings document with expect. It reads the clock through t.clock.now and prints the due time as a UTC label.

    text main(text[] argv) {
        if (argv.count() < 2) {
            return "usage: toolcrib -- <tool> <badge>"
        }
        chest? found = t.app.document("config.crib")
        if (found == null) {
            return "no crib settings"
        }
        chest settings = found
        expect { duration loanPeriod } = settings else {
            return "crib settings refused"
        }
        loans.rules.loanRequest request = { tool = argv[0], badge = argv[1], takenAt = t.clock.now() }
        timepoint<unix> due = loans.rules.dueAt(request, loanPeriod)
        return `{request.tool} out to {request.badge}, due {t.time.unix.toCivil(due)}`
    }
    # $ tricli toolcrib -- torque-wrench-14 B-2231
    # torque-wrench-14 out to B-2231, due 2026-10-22T04:11:25.1838881Z
  5. Pin the rule with test cases. A source test lives in an _test/ folder beside the module it checks, and each case in its header is a typed row. tri --test toolcrib runs both cases against one compiled program, and a failing case names itself, its assertion and the values it saw.

    # a/loans/_test/due.tri
    #{
      u16 schemaVersion = 1
      chest[] cases = [
        {
          text name = "shift loan is due twelve hours later"
          chest arguments = { duration period = 12h, timepoint<unix> expected = 1760043200 }
        },
        {
          text name = "weekend loan crosses two days"
          chest arguments = { duration period = 2d, timepoint<unix> expected = 1760172800 }
        }
      ]
    }
    bool main(duration period, timepoint<unix> expected) {
        loans.rules.loanRequest request = { tool = "torque-wrench-14", badge = "B-2231", takenAt = 1760000000 }
        timepoint<unix> due = loans.rules.dueAt(request, period)
        assert (due == expected, "due time")
        assert (loans.rules.overdue(due, expected + 1s), "one second late is overdue")
        return true
    }
What happened

Mechanics on 2nd shift check tools out at the crib terminal, and every loan carries an exact due time. The app refuses to start when its settings document is missing. When a later edit tried to send the foreman an overdue notice over HTTP, the launch stopped at the grant check and named the call.

How an MTK application is put together

An MTK application is one folder. The a/ folder holds the Trident source, and each .tri file under it is a module named by its path: a/loans/rules.tri is the module a.loans.rules. The entry is always a/main.tri, so the runtime never searches for one.

Each folder whose name starts with _ holds a fact about how the program is built and run. The runtime reads only a/ and those registered names; a readme or a docs/ folder beside them belongs to the author.

A launch is identified by three digests. The program digest covers the source and the schemas it is typed against. The deployment digest covers settings, seed rows, the platform and the build profile. The host document digest covers the grant and the host's own facts, so an operator can change a limit without changing what the program is.

  • a/: the program, one module per .tri file, with a/main.tri as the entry
  • _app/: the identity in app.draft and the settings documents the program reads
  • _db/: one stored collection per trove file, with its seed rows and migrations
  • _grant/: the lend, which narrows what the host offers; the program cannot read it
  • _host/: the store record, credential references and limits for one node
  • _target/ and _profile/: one folder per platform and one document per build profile
Shell

The tool-crib folder

Module names come from paths, and tests sit beside the code they check. Nothing lists the files a second time.

toolcrib/
  a/
    main.tri                 module a.main, the entry
    loans/rules.tri          module a.loans.rules
    loans/_test/due.tri      a source test; never shipped
  _app/
    app.draft                id, name and major version
    config/crib.draft        settings the program reads
  _db/troves/toolLoan.tri    the stored collection
  _grant/grant.draft         the lend
  _host/host.draft           host facts for one node
  _target/linux/             one folder per platform
  _profile/release.draft     the release build profile

The language and runtime

Trident states every type, bounds every loop and checks every enum branch when the program compiles. A computed value never converts on assignment. A conversion is written as the type it converts into, such as i64(count), and a lossy one is named, such as t.math.castSaturating.

Before main runs, the runtime works through a fixed prelude. It resolves and compiles the source, checks the grant and runs on configure. Then it opens stores, recovers jobs, reconciles troves, applies seed rows, builds assets and delivers on start. A step that fails is a false start: main never runs, and the failure names the step.

A fault is a value with a reason, a message and a call chain. on error and a task region's else arm catch faults raised while the program runs. A syntax error, a type mismatch or a grant that does not cover the program stops the launch before any handler exists.

Trident

The program votes on its own launch

on start is the last step of the prelude, just before main; returning a document refuses the launch. on stop runs once on every exit and reads why.

on start(const launch) {
    chest? found = t.app.document("config.crib")
    if (found == null) {
        chest refusal = { text reason = "crib settings missing: _app/config/crib.draft" }
        return refusal
    }
}

on stop(const details) {
    text cause = details.cause
    t.log.info("toolcrib stopped: " + cause)
}
Shell

A false start names its step

With the settings document removed, main never runs. The refusal document, the step and the stop cause each print on their own line.

$ tricli toolcrib -- torque-wrench-14 B-2231
text reason = "crib settings missing: _app/config/crib.draft"
tricli: falseStart: start
toolcrib stopped: falseStart

Data systems

MerTekTypes is the one table of value types. A Trident local, a MerDB column and an encoded field all spell their types from it, so a duration is the same exact span in all three.

MerDB keeps records in troves. A trove file declares each column's type and default and names its indexes. Code writes with verbs on the trove's name, such as toolLoan.insert, and a query runs only through a declared index. The prelude reconciles every trove with the store before main runs.

Rune is the typed byte form of a record. The bytes carry every field's name and complete type. The same bytes serve in memory, in MerDB and on the network, and a receiver checks them before it reads a field.

Trident

The loan ledger as a trove

Columns state their types and defaults, and byBadge is the declared path for "which tools does this mechanic hold". A value of the trove type gets its id when it is made.

# _db/troves/toolLoan.tri
trove toolLoan {
    text tool = ""
    text badge = ""
    timepoint<unix> takenAt = 0
    timepoint<unix> dueAt = 0
    index byBadge = badge
}

# a/loans/ledger.tri
toolLoan checkOut(rules.loanRequest request, duration period) {
    toolLoan loan = {
        tool = request.tool
        badge = request.badge
        takenAt = request.takenAt
        dueAt = rules.dueAt(request, period)
    }
    return toolLoan.insert(loan)
}

Rendering, assets and compute

Thalassa renders the scene a program declares. The program decides what to show; Thalassa decides how to draw it on a watch, a tablet, a desktop or a headset, within each device's screen, memory and graphics limits. Every graphics backend is checked against a software reference image.

Nautilus is the one import edge for outside asset formats. A source file under _assets/ is named by its path, so _assets/texture/hero.png is the asset texture.hero. An importer turns GLB, PNG, JPEG or FBX into MTK's own mesh, texture, rig and animation profiles, and renderers read only those profiles.

Keel holds the shared math: geometry, collision, simulation, statistics, text kernels and inference. A Keel function takes its thresholds from Trident and returns a typed result, and the decision about what to do with that result stays in the source.

Thalassa

One declared scene, drawn to fit each device.

Nautilus

Outside formats imported once, into MTK profiles.

Keel

Shared math that takes its parameters from Trident.

Host and device boundaries

A host is the executable that runs the program. tricli runs one call and opens no device. tri runs a session with windows, audio, input and camera, or runs headless as a service. Both use one runner, so a program means the same thing under either.

The host builds one grant at launch. It starts from what the executable can supply, and the application's _grant/grant.draft narrows it: revoke removes libraries, and anchor rows confine file access to named folders. The compiler derives the program's reach, and a reached library the grant does not cover stops the launch at the grant step.

Devices arrive as data. A session passes surfaces, input devices and audio devices to the program as keyed sets in each frame's input. The program asks for a change by returning a request row. A program never holds a socket, a file descriptor or a process id, and it reads no environment variables.

Fathom is the host side at scale: replicas writing one store, a parent and its worker processes, and peers on other nodes, with every joint lent by the host. BenthOS, a device operating system written in Cutlass, runs the same application folders on purpose-built devices.

Chest

The crib lends itself no network

Each revoke entry is a library id, listed in ascending order. Everything else the host offers stays available.

# _grant/grant.draft
# The crib app needs no network and starts no programs.
u16 schemaVersion = 1
text[] revoke = ["t.net.http", "t.proc"]
Shell

A new network call stops at launch

A later edit added an overdue notice that posts to the foreman's endpoint. The launch refused before main and named both the call and the grant line that revokes it.

$ tricli toolcrib -- torque-wrench-14 B-2231
tricli: lend: revoked: t.net.http
tricli: a/ reaches t.net.http.post, and _grant/grant.draft revokes t.net.http
tricli: falseStart: grant

MTK, Alba and MT9

MerTek is home to Trident and Cutlass. MTK runs Trident applications on a C runtime across devices. Alba is Furth Fortune's separate C# platform for server-side web applications: JSON definitions describe tables, service calls and events, and Wayland writes the matching C#, TypeScript, JavaScript and SQL. Alba runs on PostgreSQL and Redis, has its own codebase and does not run Trident.

MT9 is the earlier MerTek generation. MTK keeps its product shape, the Trident language contract, one document format for all primary data, and the rule that an application is configuration plus .tri source. It rebuilt the layers underneath and reads no MT9 wire format.

The type table shows the difference. MT9 kept four copies of it, for the logical types, the document format, Trident and MerDB, and ran a test to keep them aligned. MTK keeps one table in MerTekTypes, and every layer reads it.

MTK

Trident applications on a C runtime, from a command-line check to a headset or a service. One folder of source and configuration per application.

Alba

Server-side web applications in C#, generated from shared JSON definitions and run on PostgreSQL and Redis.

MT9

The earlier generation. MTK keeps its product shape and language contract and replaces everything underneath.

FURTH FORTUNE / ENGINEERING REFERENCEBack to top ↑