Operating

The App Studio screens you run an installed app from — deployments, executions, variables, usage, traces, settings and anatomy — and what each one is good for.

Once your app is installed, App Studio in the Cockpit is where you watch it and change it. This page is what each screen is for and which question it answers, so you know where to go at the point something is wrong.

Deployments

Every version you have built, when it was built, whether the build succeeded, and which one is active.

Use it to answer "what is actually running?" — the first question in almost every investigation, and the one people assume they know. A tenant can be on an older version than the one you deployed last, and a build that failed leaves the previous version serving.

For a git-wired app, this screen also shows each deployment's commit. A deployment with no commit association is the fingerprint of a CLI deploy onto a git-wired app.

Executions

One record per invocation: when, what triggered it, how long it took, the status, and the log lines your handler wrote with c.log().

This is the screen you spend the most time in. It answers:

  • Did the call reach me? A request that is not here was rejected by the gateway before your function ran — usually contract validation.
  • Did the schedule fire? Ticks appear here like any other invocation, with the schedule name.
  • Did the event arrive? So does an event delivery. This is how you find out whether an event you listened for is real. See Events you receive.
  • What did my handler think it was doing? Whatever you logged.

Which is the argument for logging deliberately: one line per invocation with the request id, the tenant and the outcome turns this screen into something you can search. And the argument against logging carelessly: never log a sensitive setting or personal data, because this screen is readable by whoever operates the tenant.

Variables

Environment variables for the app, per tenant. This is where the OTEL_* tracing configuration goes, and any other non-secret configuration your runtime needs.

Two things it is not:

  • Not the place for merchant configuration. Anything a merchant should be able to change belongs in settings.json, where it gets a form, validation and per-market resolution.
  • Not a secrets manager. A value a merchant supplies belongs in a sensitive setting; the secret grant is not yet proven.

Changing a variable is an operational change, not a deploy. Note that a change takes effect for new invocations, not for one already running.

Usage

Invocation counts, durations and error rates over time.

Use it for the questions a single execution cannot answer: is the error rate rising, is the p99 a real tail or one pathological request, did that release change the shape of the traffic, and is this app being called at all. An app with zero invocations after a launch is a routing or install problem, not a code problem.

It is also where you notice a job whose cost grows with the tenant — a nightly task that took two seconds at launch and forty a year later. See Scheduled work.

Traces

The per-invocation spans, when you have configured an OTLP endpoint. Free and empty when you have not.

Executions tell you that an invocation was slow; traces tell you where. Use them for the two questions that matter most in a commerce app: is my own code slow, or is something I call slow — another app's capability, or an external host. Forwarding X-Request-ID is what makes that chain one trace instead of three. See Tracing.

Settings

The rendered settings.json form for this tenant: the current values, per market where a key is market-scoped.

Use it to answer "what is this tenant actually configured with?" — and to check the form you shipped is one a merchant can use, which is easier to judge here than in the JSON. The settings endpoint gives you the same answer from a terminal.

When an operator reports that a change had no effect, this screen plus the market they were testing with usually explains it.

Anatomy

What the app declares, as the platform understands it: its entities, its capabilities and routes, its grants, its events and schedules.

This is the screen for "is what I think I declared what actually got applied?" It is generated from the applied version, not from your working copy, so it is the authoritative answer when a route is missing or a grant is not doing what you expected. Read it alongside the published OpenAPI document, which is the same information from the caller's side.

What healthy looks like

Four things, all observable without instrumenting anything.

  • The active version is the one you shipped. Deployments answers this.
  • Invocations are not zero. An app with none after a launch has a routing or install problem; nothing is reaching it.
  • The error rate is flat, and the p99 is a population rather than one request. A single pathological request moving the p99 is a different problem from a tail that is getting worse.
  • Every schedule you declared appears. A schedule that stopped firing is silent by construction: nobody gets an error, the work just does not happen.

Nothing on the platform pages you for any of this, and there is no alerting to configure (as of 2026-10), so "watch" means you open the screen, on a rhythm you decide. After every release, at minimum.

After each release

Three screens, in this order. It takes a minute.

  1. Deployments. The version you just shipped is the active one, and the build succeeded.
  2. Anatomy. The routes, grants, events and schedules you think you declared are the ones that got applied.
  3. Usage. The error rate after the release looks like the error rate before it.

Then re-run the live checks, including the POST /defaults call. It is idempotent, so it belongs in your deploy script rather than in a runbook nobody reads, and app.installed does not reliably fire on a Marketplace install.

Watching the work nobody calls

Scheduled jobs and outbound calls fail quietly, because no caller is waiting on them.

Schedules. A tick is one tenant, so the job's cost is your slowest tenant times the number of tenants, and it eventually times out on the tenant with the most data. Make the job return what it did: the return value lands in the execution record either way, so { scanned: 4210, expired: 17 } costs you nothing and {} tells you nothing.

Outbound HTTP. A call to an external host fails as your own 502 or as a timeout, so it looks like your app failing. There is no separate egress screen; you find these in Executions. What keeps them rare is a timeout on every external call and no third party on a path the storefront awaits. Enforcement for your outbound declarations is still being built, so an undeclared call currently succeeds (as of 2026-09), and an app whose register is wrong will break when enforcement lands. Keep it honest now.

Whose failure is it?

Where a failure happened decides which screen is any use. For the same question asked of any gateway call, not only an app's, Debug a failed request walks from the response to its cause. This table is the app-specific cut of it.

What the caller gotWhere it happenedWhat to look at
400 on a POST you are sure aboutGateway, before youMissing body, or a request schema stricter than your handler. Send {} rather than no body
401GatewayThe credential, not your app
404 on your pathGatewayThe install did not run for this version, or the app is not installed on this tenant
429GatewayA rate limit. The caller handles it; there is no setting to change
403 on a writeYour handlerThe entity grant does not cover that operation. The invocation ran, so Executions has it
400, 403, 404, 409 you raisedYour handlerYour own guard or constraint. Executions has the log line
502Your handlerYour function threw, or something it called did. Read the execution

The four gateway rows are the ones worth internalising: the tenant sees a failure you have no record of. If a partner reports errors you cannot find in Executions, stop looking at your code and look at the contract and the install. Anatomy and the published OpenAPI document are the two places that answer it.

If the slow part is a cold start on a latency-sensitive path, a capability the storefront or checkout awaits, warmup is the switch. It is not free, so it is a decision per app rather than a default. Still wrong? Check status.revenexx.com before you write anything; an incident there is already being worked.

What to hand over when you escalate

A support request that gets answered in one round trip carries these. Gather them before you open it, not after someone asks.

  • The X-Request-ID of a failing request. A refusal from the gateway itself does not echo one, so quote the ID the caller sent.
  • The tenant slug you sent in X-Revenexx-Tenant.
  • The endpoint, the method, and the timestamp in UTC, not "this morning".
  • What you expected and what you got: the real status and body, not a paraphrase.
  • The active version from Deployments, and whether the failure started with a release.

Requests go to support.revenexx.com. There is no separate developer queue. A page that is wrong or unclear goes somewhere else, the "Was this page helpful?" control at the bottom of it, because nobody triages an outage from a docs issue. See Get help.

Which screen for which question

QuestionScreen
What version is running here?Deployments
Did my request reach the app?Executions
Why is it slow?Traces, then Usage
Is it getting worse?Usage
Did the schedule or the event fire?Executions
What is this tenant configured with?Settings
Did my declaration actually apply?Anatomy
Where does the OTLP endpoint go?Variables

Next steps

Was this page helpful?