Furth FortuneEngineering reference
TECHNICAL DOCUMENTATION

2027 · MerTek technology

On this page

Engineering reference / System overview

Controlled Deployment

Two update paths: live generations and staged nodes

MTK updates running software along two paths. Trident source and configuration changes publish a validated application generation that goes live between calls. Runtime and driver changes move through a staged node rollout, with every transition recorded and the previous generation kept for rollback.

Worked example

An approval-rule change at noon and a driver fix over a week

The Tulsa depot runs its readiness application on 140 nodes: handhelds, bench stations and two servers. On Tuesday the parts lead wants repair orders open more than 30 days to need a second approval. On Wednesday the platform team ships a runtime build with a barcode-scanner driver fix. The rule change must land in minutes; the driver fix must never take the whole floor down at once.

  1. The engineer edits one module and checks it as a candidate. t.code.check runs the same compiler and verifier the host will run, so a candidate that fails here never becomes a generation.

    chest candidate() {
        chest row = {
            text moduleId = "a.approval",
            text source = "bool needsSecondApproval(u32 openDays) {\n    return openDays > 30\n}\n"
        }
        chest[] modules = [row]
        chest map = { u16 schemaVersion = 1, text entryModule = "a.approval" }
        map.modules = modules
        return map
    }
    
    text main(text[] argv) {
        chest verdict = t.code.check(candidate())
        chest[] faults = verdict.faults
        if (faults.count() > 0) {
            return "refused: " + text(faults.count()) + " faults"
        }
        return "ready to publish"
    }
  2. The application asks its host for the replacement as a row in its result, never as a call. merge keeps every module the edit does not name, and adopt keeps live peer connections. The host compiles the whole program, installs it between calls, and keeps generation 184 as the rollback point.

    chest replaceRequest(u64 generation, chest moduleMap) {
        chest program = { text origin = "authored", u64 sequence = 0 }
        chest? source = moduleMap
        guid? connection = null
        program.source = source
        program.connection = connection
        chest payload = { text compose = "merge", text connections = "adopt" }
        payload.program = program
        chest request = { text kind = "programReplace" }
        request.generation = generation
        request.payload = payload
        return request
    }
  3. The driver fix is a new runtime, so it takes the node path. Each node runs the release its tri.draft pins, and a runner of another version refuses at the argument stage. The runner also checks its own image bytes against the pinned digests. Five bench stations get the new pin first.

    # The runtime release this node runs, and the runner images it accepts.
    text release = "1.0.2"
    sha256 releaseDigest = "a41c97e2b0d35f8861c4e2f09b7d3a6e5f1c8b2d4e6a7f9031c5b8d2e4f6a7b9"
    sha256[] releaseRunners = ["0c9e4d1b7a3f5e2c8d6b4a1f9e7c5b3d2a4f6e8c1b3d5f7a9e2c4b6d8f1a3c5e"]
  4. A node installs a runtime as one complete generation and moves one pointer. The old generation stays on disk, so rollback moves the pointer back, and a running process keeps the generation it started with.

    ~/.mertek-trident-cache/
      <sha256>                 # one blessed object: tricli, tri, or the launcher
      releases/<sha256>/       # one release: its public manifest and its artifact set
      generations/<sha256>     # immutable descriptor: tricli, tri, launcher, release
      pins/active              # one atomic reference to a complete descriptor
      trust/                   # durable highest accepted signed-index generation
  5. Blue and green serve together. Pilot nodes on 1.0.2 and the other 135 on 1.0.1 share one wire. The handshake refuses only a different protocol identity, and each side reads any other difference as a fact. The application plan stays pinned by digest the whole time.

    # The application plan this node runs, pinned by its digest.
    # A substituted plan file refuses before any provider opens.
    text plan = "/srv/depot/readiness/plan.chest"
    sha256 planDigest = "5d1f0c3a9e8b7d6c5b4a3928170f6e5d4c3b2a19087f6e5d4c3b2a1908f7e6d5"
What happened

Generation 185 went live at 12:06; a request in flight finished on 184, and the next one ran the new rule. The driver fix reached 5 nodes on Wednesday, 25 on Thursday and all 140 by Monday. When 9 handhelds of one model showed scan failures, the team paused the wave and moved them back to the previous runtime in one step.

System diagram

Choose the update path by change type

Application policy can move without replacing the compiled node. Runtime changes use staged rollout and rollback.

Approved change what changed?
App path .tri + config • live generation
Node path runtime + driver • staged image
Observed state active version + rollback point

Inside the system

How the parts work together

Follow the data, decisions, and access boundaries. Each diagram explains a concept used by applications.

Map 01

Commit is not a generation

Stored source becomes fieldable only after validation and publication.

  1. Source commit durable edit
  2. Validation parse + gates
  3. Generation published application
  4. Activation selected runtime state
Map 02

Compiled rollout state

A node update advances through durable states one transition at a time.

  1. Prepared artifact + policy
  2. Staged target group
  3. Serving health observed
  4. Expanded or rolled back recorded transition
Map 03

Blue and green overlap

Current and incoming fleets serve together until the cutover is proven.

  1. Blue current nodes
  2. Compatible wire shared service contract
  3. Green incoming nodes
  4. Cutover health + policy
Map 04

Known starting state

Both update paths begin from a recorded genesis version and configuration.

  1. Genesis trusted baseline
  2. Current state version + config
  3. Proposed change declared delta
  4. Next state auditable result

Key parts

What the system does

These are the main boundaries, inputs, outputs, and failure rules. The examples show a specific use of each part.

Application path: live generations

Trident source and configuration change through a published generation: checked, compiled whole, then installed between calls. The retained state carries over, and the previous generation stays as the rollback point. A candidate that fails to compile changes nothing.

For example

The second-approval threshold moves to 30 days on generation 185 while handhelds keep scanning.

Node path: staged rollout

A runtime or driver change installs as a complete node generation and widens in recorded waves: prepared, staged, serving, then expanded or rolled back. Each transition is a durable record, and rollback selects a retained generation instead of rebuilding one.

For example

A scanner-driver fix reaches 5 bench stations, then 25 nodes, then 140. Every wave traces back to the depot's genesis baseline.

Blue/green on a compatible wire

Old and new nodes serve together until the cutover is proven. The handshake refuses only a different protocol identity. Other differences are facts each side reads, per declared handler and per trove, never per build.

For example

A handheld still on 1.0.1 keeps syncing with a server on 1.0.2, because every handler it calls kept its signature.

Code

Controlled Deployment in code

Each example is short and complete enough to read on its own. Hover a dotted word for its definition.

Trident

Read why a candidate was refused

A candidate that compares a u32 with 30.5 is refused before anything is published. t.code.faultText renders each fault exactly as the runner would, here an L.real refusal at line 2, column 23 of a.approval.

text report(chest candidate) {
    chest verdict = t.code.check(candidate)
    chest[] faults = verdict.faults
    text out = ""
    foreach (fault in faults) {
        out = out + t.code.faultText(fault) + "\n"
    }
    return out
}
Trident

One module map, one program digest

Compiling the same module map always gives the same digest. The generation a reviewer checked and the generation a node runs are provably the same program.

text digestOf(chest candidate) {
    chest compiled = t.code.compile(candidate)
    sha256 program = compiled.programDigest
    text entry = compiled.entryModule
    return entry + " " + text(program)
}
Trident

A replacement hears every connection it kept

Under adopt, the new generation receives one peerAdopted event per live connection before any message reaches it. A replacement that declares no handler for a kept connection's events is refused at install, and the old generation keeps running.

chest main() {
    chest state = {}
    return state
}

on event("peerAdopted", const chest fact) {
    text endpoint = fact.endpoint
    t.log.info("generation 185 kept a connection on " + endpoint)
}
Trident

Start and stop around a node swap

on start is the launch's vote: reaching the end of the block accepts the launch, and stop inside it refuses. on stop reads why the runtime ended, such as finished or stopped, and cannot veto it.

on start(const launch) {
    on exit { t.log.info("start vote recorded") }
    t.log.info("readiness node starting")
}

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

text main(text[] argv) {
    return "serving"
}
Chest

The application's identity does not move

A generation changes source and configuration. It never changes the application's id or its declared major, so every generation stays one application in the control plane's records.

# The application's identity, shared by every generation.
text id = "mertek.depotreadiness"
text name = "depotReadiness"
u32 major = 1

Uses

Example uses

  • Rule and workflow changes during a shift
  • Runtime and driver updates across a mixed fleet
  • Pilot groups with a one-step way back

Review questions

What the team must decide

Which changes are source and configuration, and which need a new runtime

How large the first wave is, and what stops a wave

How long old and new runtimes must share the wire

Contact us
FURTH FORTUNE / ENGINEERING REFERENCEBack to top ↑