Skip to content
Developer Tools

Center Debugger

The Center ships a stop-the-world debugger for server-side AmiScript: timers, triggers, procedures, and methods. It freezes the Center actor thread at a breakpoint and lets you inspect and step from a plain command surface: no IDE, no second JVM, no separate protocol. The same debugger backs the editor experience over DAP; this page is the direct command syntax you drive from MCP tooling or the admin console.

Note

The debugger is enabled by default. Setting ami.db.debug.enabled=false removes it: with the flag off there is zero runtime path, and breakpoints never fire.

Enabling

The flag defaults to true. To set it explicitly, use the Center's local.properties:

ami.db.debug.enabled = true

Restart AmiCore to pick it up. A breakpoint armed while the flag is off is remembered but will not fire until the flag is set and the target is (re)started. The arm command warns when this is the case.

How It Works

When execution reaches an armed line, the debugger blocks the Center actor thread in place. It does not unwind. The whole Center freezes at a consistent point, holding the partition write lock, so nothing else mutates state while you inspect. Because the frozen actor holds that lock, normal queries cannot run; instead the debug commands travel a lock-free command pump that the frozen actor services, so status / backtrace / step / resume all work while everything else is paused.

The Center is frozen while paused

A breakpoint hit stops the entire Center, not just one session. Normal queries are rejected with a "locked debug state" message until you resume, continue, or abort. Arm breakpoints deliberately, and use the idle auto-resume safety net.

Issuing Commands

The command surface is one string, reachable 3 ways:

Surface Form
MCP center_debug(command="<subcommand>")
Admin console center_debug <subcommand>
Query any statement beginning with debug (e.g: debug status) is routed to the debugger instead of the query engine

All three parse the same vocabulary. The MCP/admin form is lock-free and works while the Center is frozen; the query form cannot pause behind the frozen actor, so prefer center_debug for anything issued during a freeze.

Target IDs

A breakpoint names its target with the Center grammar:

1
2
3
4
5
6
center:<kind>:<name>:<slot>
    kind = timer | procedure | trigger | method
    e.g.  center:timer:myTimer:script
          center:procedure:myProc:script
          center:trigger:myTrig:onInsertingScript
          center:method:myMethod:script

The <slot> is the script slot within the object: script for a timer/procedure/method, or the specific handler (onInsertingScript, onUpdatedScript, …) for a trigger.

Command Reference

1
2
3
status | arm <targetId> <line> | clear <targetId> [<line>] | clearall
| coverage startup|shutdown|pause|resume|reset|report [targetId] | backtrace | locals [frameId] | eval <expression>
| query <sql> | step | stepin | stepout | resume | continue | abort | detach

Breakpoints (Armed Any Time, No Freeze Needed)

Command Effect
arm <targetId> <line> Set a breakpoint at a source line of a target.
clear <targetId> <line> Remove one breakpoint.
clear <targetId> Remove all breakpoints on a target.
clearall Remove every breakpoint.
status Show whether the debugger is enabled, whether it is frozen, and (if frozen) the target, line, and paused statement.

Inspecting a Frozen Target

Command Alias Returns
backtrace bt The call stack, one row per frame (Frame, Scope, Line, Statement).
locals [frameId] The in-scope variables of a frame (frame 0 = innermost): Name, Type, Value.
eval <expression> print, p Evaluate an AmiScript expression in the frozen frame's scope (locals visible) e.g: eval x + 1.
query <sql> Run a read-only SELECT against the frozen Center's tables e.g: query SELECT * FROM Orders.

eval is for a value in the paused scope; query is for the database. Both run without unfreezing.

Advancing Execution (Terminal: They Release the Freeze)

Command Alias Effect
step next, stepover Run any call on this line to completion, stop at the next statement in this target.
stepin into, stepinto Descend into a call/method on this line, stop on the callee's first statement.
stepout out, finish Run the rest of this target, stop at the caller's next statement.
resume Run to the next breakpoint.
continue Run to completion, breakpoints disabled for the rest of this run.
abort Unwind the frozen execution immediately.

After a step, run status to see the new position.

Coverage

coverage startup|shutdown|pause|resume|reset|report [targetId] records line and branch coverage without freezing:

  • startup: start recording.
  • pause: stop recording and keep the results.
  • resume: start recording again.
  • reset: discard the results and keep recording.
  • shutdown: stop recording and discard the results.
  • report: show the results, or the expressions of one target.

See Code Coverage.

detach

An operator escape hatch: an IDE (DAP) attach takes an exclusive controller claim, and a client that dies without releasing it (crash, half-open socket) would otherwise hold the debugger until the Center restarts. detach drops that claim. It is lock-free and safe whether or not the Center is frozen. It releases the claim only, and does not resume the actor.

A Session

# arm a breakpoint, then let the timer fire
center_debug("arm center:timer:priceRoll:script 4")
  => armed center:timer:priceRoll:script line 4

# ... the timer fires and the Center freezes at line 4 ...
center_debug("status")
  => enabled=true  frozen=true  targetId=center:timer:priceRoll:script  line=4  statement=...

center_debug("backtrace")
center_debug("locals")            # variables in the innermost frame
center_debug("eval spread * 2")   # evaluate an expression in scope
center_debug("query SELECT count(*) FROM Orders")

center_debug("step")              # advance one statement
center_debug("continue")          # finish the run

Idle Auto-Resume

A breakpoint that no one is driving cannot freeze the Center forever: after an idle window (ami.db.debug.idle.resume.millis) a frozen-but-untouched breakpoint auto-resumes. This keeps a walked-away debug session, or a controller that vanished, from wedging the deployment.

Single Controller

An IDE (DAP) attach takes an exclusive controller claim, so a second attach is refused with a message naming the current holder instead of two editors interleaving steps on one frozen actor. The claim is released when that session detaches, or with detach when the client died without releasing it.

The claim does not lock out this command surface

center_debug keeps working while a DAP session holds the claim. That is deliberate, and it is what makes detach usable when the IDE client is wedged. The consequence is that a step or resume issued here will advance a freeze an attached editor is driving, and the editor will then be showing a position that no longer exists. When someone is attached, either coordinate with them or detach first.

  • Language and Debug Servers: the LSP/DAP servers that expose this debugger to your editor over the DAP protocol.
  • Code Coverage: the coverage verb and the coverage the debugger records.
  • Unit Testing: the isolated test runner, which reuses this debugger's per-statement hook to measure coverage.