Furth FortuneEngineering reference
TECHNICAL DOCUMENTATION

2027 · MerTek technology

On this page

Engineering reference / System overview

Operational Debug Views

See inside a running program without touching it

A running tri program publishes copies of its state to a separate Wheelhouse process over an authenticated debug association. What the debugger may do and what data it may see are checked as two separate questions. Scene overlays and service panels draw the same typed facts.

Worked example

A pump schedule that stopped advancing at 02:10

The Harlan County water utility runs its pump scheduler as a headless tri service. At 02:10 the schedule for Station 7 stops advancing while the other five stations keep running. The on-call engineer works from home, and the service has to keep serving. The customer billing records it holds are off limits to on-call staff.

  1. The operator declared debugging before the incident. The service's debug document opens one endpoint and pins each on-call engineer's key at observe. That level reads and captures but can never stop a call. Debug memory comes from its own budget, maxDebugBytes, so building a snapshot can never fail a call that would have succeeded.

    # _host/s/debug.draft: who may look inside the scheduler, and how far.
    u16 schemaVersion = 1
    u64 maxDebugBytes = 67108864
    chest[] members = [
        {
            text constructorId = "debugEndpoint"
            text key = "oncall"
            chest config = {
                text position = "listener"
                text carrier = "plaintext"
                ip address = 10.20.0.15
                u16 port = 7400
                chest[] principals = [
                    {
                        u8[32] principal = [
                            41, 7, 188, 92, 13, 250, 66, 141, 9, 202, 37, 118, 75, 3, 164, 29,
                            210, 58, 97, 133, 6, 241, 84, 19, 172, 45, 230, 101, 62, 155, 8, 217]
                        text[] levels = ["observe"]
                    }
                ]
                text pausePolicy = "suspendBudgets"
            }
        }
    ]
  2. Ask the timer subject which timers are pending. Every subject answers the same request shape: a subject name, a key and a window. The host takes one reading between two calls, so the answer names the last committed call and never a half-run one.

    # debugger -> target
    text kind = "observeRequest"
    u64 request = 8
    text subject = "timer"
    text key = "session"
    chest window = { u64 start = 0, u64 count = 20 }
    
    # target -> debugger: five session timers, where six stations run
    text kind = "observation"
    u64 request = 8
    text subject = "timer"
    text status = "ok"
    u64 generation = 41
    u64 total = 5
    guid trace = 3f2c9a10-7b4e-4c21-9d8a-0e5f6a7b8c9d
    u64 span = 418233
    u64 parentSpan = 1
    u64 runtime = 1
    bool after = true
    chest? callFirst = null
    u64 content = 4
    u64 size = 1912
  3. Capture the hot path without stopping it. A capture point publishes a snapshot and lets the call continue, under a count and spacing the debugger declares. Snapshots at the line that stores each gauge reading showed Station 7's level arriving null.

    # debugger -> target: at most 5 captures, at least 1 s apart
    text kind = "capturePoints"
    u64 request = 9
    text sourceUnit = "a.gauges"
    u64[] lines = [58]
    u32 limit = 5
    u64 spacing = 1000000000
    
    # target -> debugger: the call kept running; its snapshot follows as content
    text kind = "snapshot"
    u64 request = 0
    text reason = "capturePoint"
    u64 calls = 418236
    text cause = "published"
    u64 dropped = 0
    u64 refused = 0
    u64 stateGeneration = 96114
    u64 sceneGeneration = 0
    u64 content = 5
    u64 size = 22816
  4. A pause asked at observe is refused. Stopping a call stalls every request the runtime serves, so control is a separate level the operator grants by name. The receipt says level, nothing changed, and the service kept serving.

    # debugger -> target
    text kind = "pause"
    u64 request = 10
    
    # target -> debugger
    text kind = "receipt"
    u64 request = 10
    text status = "level"
    u64 calls = 418240
    text[] levels = ["observe"]
  5. Reproduce the faulted call offline. The service keeps a rolling flight-recorder tape, so the engineer replays the call that faulted in a separate child with every effect denied. The replay shows each frame as it stood and reaches no live store, sensor or billing record.

    # How the service runs: headless, keeping the most recent calls on tape.
    tri --headless --flight-recorder 268435456 /opt/pumpsched
    
    # On the engineer's machine: replay the tape, pinned to its digest.
    tri --replay /home/oncall/pumpsched-0210.tape --tape-digest <tape-digest>
    # A read the tape did not capture answers captureIncomplete;
    # the replay refuses rather than guess or reach the live world.
What happened

Station 7's level gauge went offline at 02:09, its reading came back null, and the timer handler faulted before it re-armed the station's timer. The engineer found that at observe, never paused the service and never saw a billing row. The fix holds the last schedule when a reading is missing, and the replayed tape became its regression test.

System diagram

One fact model, two views

The overlay and service panel read the same typed facts. Neither view changes application behavior.

Debug facts route input • bounds • 18 ms
Scene overlay path + object boxes
Service panel queue + last commit
Review record same event and timestamp

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

Data first, drawing second

Subsystems publish typed facts. C lays them out and Glint draws them, and neither decides what a number means.

  1. Subsystem typed debug facts
  2. Debug model shared shape
  3. C layout view preparation
  4. Glint render-only overlay
Map 02

Two additive products

A normal product view and a debug overlay use one visibility rule.

  1. Product scene application view
  2. Debug facts optional data
  3. Visibility policy role + setting
  4. Composed output no behavior change
Map 03

Stage anatomy

Each overlay stage owns one input, one visual result, and one declared setting.

  1. Stage input typed data
  2. Stage setting enabled + options
  3. Stage output lines • labels • bounds
  4. Shared overlay additive composition
Map 04

Declared settings and state

A view reports the setting it asked for, the setting that is active, and why any part of it is unavailable.

  1. Requested setting declared choice
  2. Capability check supported?
  3. Active state resolved setting
  4. Reported state visible reason

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.

A separate process, copied state

The debugger is Wheelhouse, in its own process and window. The target is an ordinary tri session. Every debug snapshot crosses as a copied Chest document that the debugger validates as hostile input, so neither side can write the other's memory.

For example

A breakpoint blocks the target's VM thread at a poll point, while Wheelhouse keeps drawing and taking input in its own process.

Debug level and data authority

The debug document grants levels per principal: observe, control, mutate and reveal. Seeing protected data is a separate check against the viewer's own grants. A pause stops the call's wall budget and the session clock, never security time, so revocations and grant changes are checked again on resume.

For example

A snapshot or replay supplies observations and never live authority. An on-call key at observe sees a stored password verifier only as its kind, length and digest.

One fact model, two views

Systems publish typed facts: state, events, timings and boundaries. A rendered app draws them as a scene overlay, and a headless service shows them in a service panel. Both read the same documents through one request shape.

For example

A frame overlay and the job panel name the same call span. A reviewer can line up a rendered frame with the job that fed it.

Code

Operational Debug Views in code

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

Shell

Start a debug session three ways

A development launch can hold the session until Wheelhouse attaches. A remote engineer reaches a declared endpoint. A client behind NAT dials a support debugger that listens.

# Development: Wheelhouse attaches before the first call runs.
tri --debug --stop-at-entry pumpsched

# Support behind NAT: the support debugger listens ...
wheelhouse --debugger --listen 203.0.113.40:7411
# ... and the customer launches the client with support's host file,
# whose debug document declares a connector endpoint at that address.
Chest

The member a paired debugger receives

On the author's own machine, script mode grants a paired debugger all four levels. A release launch carries an empty set unless its own debug document declares one.

text constructorId = "debugPaired"
text key = "author"
chest config = {
    text[] levels = ["observe", "control", "mutate", "reveal"]
    u32? storeAudience = null
    text pausePolicy = "suspendBudgets"
}
Chest

A support endpoint that dials out

In connector position the target dials support once and admits only the principal it pins. A hijacked address reaches nobody, and launching with the host file is the customer's consent.

text constructorId = "debugEndpoint"
text key = "support"
chest config = {
    text position = "connector"
    text carrier = "plaintext"
    ip address = 203.0.113.40
    u16 port = 7411
    chest[] principals = [
        {
            u8[32] principal = [
                88, 3, 140, 27, 201, 66, 9, 115, 230, 41, 172, 18, 95, 250, 7, 133,
                64, 199, 12, 81, 157, 36, 222, 103, 49, 178, 20, 245, 90, 11, 167, 58]
            text[] levels = ["observe", "control"]
        }
    ]
    text pausePolicy = "suspendBudgets"
}
Shell

The layer rule for every view

Subsystems publish facts and hold no view. Chest carries them, scene policy decides how they look, and the renderer draws. One schema serves live views and replay.

C subsystem hooks  ->  Chest telemetry  ->  scene policy  ->  Reef and Glint

# subsystem      snapshots, counters, events, stable ids, source spans
# Chest          the same document live and on tape
# scene policy   grouping, filtering, layout, color, interaction
# Reef, Glint    retained blocks and drawing; no debug logic
Chest

One request shape, any subject

The job subject answers the same request the timers do. A subject that cannot answer says unavailable and never sends an empty document in its place.

text kind = "observeRequest"
u64 request = 12
text subject = "job"
text key = "job"
chest window = { u64 start = 0, u64 count = 50 }

Uses

Example uses

  • On-call diagnosis of live services
  • Field support for clients behind NAT
  • Replaying a faulted call from a recorded tape

Review questions

What the team must decide

Which principals need observe, and which ever need control

Which protected data each debugging role may see

How long flight-recorder tapes are kept on each node

Contact us
FURTH FORTUNE / ENGINEERING REFERENCEBack to top ↑